FELIX-4689: Create a more fluent syntax for the dependency manager builder.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1727869 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/BundleAdapterBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/BundleAdapterBuilder.java
new file mode 100644
index 0000000..8a393a1
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/BundleAdapterBuilder.java
@@ -0,0 +1,243 @@
+package org.apache.felix.dm.lambda;
+
+import org.apache.felix.dm.lambda.callbacks.CbBundle;
+import org.apache.felix.dm.lambda.callbacks.CbComponentBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentBundle;
+
+/**
+ * Builds a Dependency Manager bundle adapter. The adapter created by this builder will be applied to any bundle that matches the specified
+ * bundle state mask and filter condition. For each matching bundle an adapter service will be created based on the adapter implementation class.
+ * The adapter will be registered with the specified interface and existing properties from the original bundle plus any extra properties
+ * you supply here. The bundle is injected by reflection in adapter class fields having a Bundle type, or using a callback method that you can
+ * specify.
+ *
+ * <p> Example which creates a BundleAdapter service for each started bundle (the bundle is added by reflection on
+ * a class field that has a "Bundle" type):
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * bundleAdapter(adapt -> adapt
+ * .impl(BundleAdapterImpl.class)
+ * .provides(BundleAdapter.class)
+ * .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE));
+ * }
+ * }
+ * } </pre>
+ *
+ * Example that creates a BundleAdapter service for each started bundle (the bundle is added using a method reference):
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * bundleAdapter(adapt -> adapt
+ * .impl(BundleAdapterImpl.class)
+ * .provides(BundleAdapter.class)
+ * .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE)
+ * .cb(BundleAdapterImpl::setBundle));
+ * }
+ * }
+ * }</pre>
+ *
+ * Example that creates a BundleAdapter service for each started bundle (the bundle is added using a method name):
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * bundleAdapter(adapt -> adapt
+ * .impl(BundleAdapterImpl.class)
+ * .provides(BundleAdapter.class)
+ * .mask(Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE)
+ * .cb("setBundle"));
+ * }
+ * }
+ * }</pre>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface BundleAdapterBuilder extends ComponentBuilder<BundleAdapterBuilder> {
+ /**
+ * Sets the bundle state mask to depend on. The OSGi BundleTracker explains this mask in more detail, but
+ * it is basically a mask with flags for each potential state a bundle can be in.
+ *
+ * @param mask the mask to use
+ * @return this builder
+ */
+ BundleAdapterBuilder mask(int mask);
+
+ /**
+ * Sets the filter condition to depend on. Filters are matched against the full manifest of a bundle.
+ *
+ * @param filter the filter condition
+ * @return this builder
+ */
+ BundleAdapterBuilder filter(String filter);
+
+ /**
+ * Sets property propagation. If set to <code>true</code> any bundle manifest properties will be added
+ * to the service properties of the component that has this dependency (if it registers as a service).
+ *
+ * @param propagate <code>true</code> to propagate the bundle manifest properties
+ * @return this builder
+ */
+ BundleAdapterBuilder propagate(boolean propagate);
+
+ /**
+ * Enables property propagation. Any bundle manifest properties will be added
+ * to the service properties of the component that has this dependency (if it registers as a service).
+ *
+ * @return this builder
+ */
+ BundleAdapterBuilder propagate();
+
+ /**
+ * Sets some <code>callbacks</code> invoked on the component implementation instances. When a bundle state matches the bundle
+ * adapter filter, then the bundle is injected using the specified callback methods. When you specify one callback, it stands for the "add" callback.
+ * When you specify two callbacks, the first one corresponds to the "add" callback, and the second one to the "remove" callback. When you specify three
+ * callbacks, the first one stands for the "add" callback, the second one for the "change" callback, and the third one for the "remove" callback.
+ *
+ * @param callbacks a list of callbacks (1 param : "add", 2 params : "add"/remove", 3 params : "add"/"change"/"remove").
+ * @return this builder
+ */
+ BundleAdapterBuilder cb(String ... callbacks);
+
+ /**
+ * Sets some <code>callback instance</code> methods invoked on a given Object instance. When a bundle state matches the bundle
+ * adapter filter, then the bundle is injected using the specified callback methods. When you specify one callback, it stands for the "add" callback.
+ * When you specify two callbacks, the first one corresponds to the "add" callback, and the second one to the "remove" callback.
+ * When you specify three callbacks, the first one stands for the "add" callback, the second one for the "change" callback, and the third one for
+ * the "remove" callback.
+ *
+ * @param callbackInstance the Object instance where the callbacks are invoked on
+ * @param callbacks a list of callbacks (1 param : "add", 2 params : "add"/remove", 3 params : "add"/"change"/"remove").
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(Object callbackInstance, String ... callbacks);
+
+ /**
+ * Sets a <code>callback</code> invoked on a component implementation instance when a bundle is added.
+ * The method reference must point to a Component implementation class method, and take as argument a Bundle.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ <T> BundleAdapterBuilder cb(CbTypeBundle<T> add);
+
+ /**
+ * Sets some <code>callbacks</code> invoked on a component implementation instance when a bundle is added/removed.
+ * The method references must point to a Component implementation class method, and take as argument a Bundle.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleAdapterBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> remove);
+
+ /**
+ * Sets some <code>callbacks</code> invoked on a component implementation instance when a bundle is added, changed or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Bundle.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleAdapterBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> change, CbTypeBundle<T> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked on a component implementation instance when a bundle is added.
+ * The method reference must point to a Component implementation class method, and take as argument a Component and a Bundle.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ <T> BundleAdapterBuilder cb(CbTypeComponentBundle<T> add);
+
+ /**
+ * Sets some <code>callbacks</code> invoked on a component implementation instance when a bundle is added, or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Component and a Bundle.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleAdapterBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> remove);
+
+ /**
+ * Sets some <code>callbacks</code> invoked on a component implementation instance when a bundle is added, changed or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Component and a Bundle.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleAdapterBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> change, CbTypeComponentBundle<T> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked on a given Object instance when a bundle is added.
+ * The method reference must point to an Object instance method, and takes as argument a Bundle parameter.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(CbBundle add);
+
+ /**
+ * Sets some <code>callback instance</code> invoked on a given Object instance when a bundle is added or removed.
+ * The method references must point to an Object instance method, and take as argument a Bundle parameter.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(CbBundle add, CbBundle remove);
+
+ /**
+ * Sets some <code>callback instance</code> invoked on a given Object instance when a bundle is added, changed or removed.
+ * The method references must point to an Object instance method, and take as argument a Bundle parameter.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(CbBundle add, CbBundle change, CbBundle remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked on a given Object instance when a bundle is added.
+ * The method reference must point to an Object instance method, and takes as arguments a Component and a Bundle.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(CbComponentBundle add);
+
+ /**
+ * Sets some <code>callback instance</code> invoked on a given Object instance when a bundle is added or removed.
+ * The method references must point to an Object instance method, and take as argument a Component and a Bundle.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(CbComponentBundle add, CbComponentBundle remove);
+
+ /**
+ * Sets some <code>callback instance</code> invoked on a given Object instance when a bundle is added, changed or removed.
+ * The method references must point to an Object instance method, and take as argument a Component and a Bundle.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleAdapterBuilder cbi(CbComponentBundle add, CbComponentBundle change, CbComponentBundle remove);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/BundleDependencyBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/BundleDependencyBuilder.java
new file mode 100644
index 0000000..0c577ba
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/BundleDependencyBuilder.java
@@ -0,0 +1,279 @@
+package org.apache.felix.dm.lambda;
+
+import java.util.Dictionary;
+import java.util.function.Supplier;
+
+import org.apache.felix.dm.BundleDependency;
+import org.apache.felix.dm.lambda.callbacks.CbBundle;
+import org.apache.felix.dm.lambda.callbacks.CbComponentBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentBundle;
+import org.osgi.framework.Bundle;
+
+/**
+ * Builds a Dependency Manager Bundle Dependency. The Dependency is required by default (unlike in the original Dependency Manager API).
+ *
+ * <p> Example of a Component which tracks a started bundle having a given bundle symbolic name:
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * String BSN = "org.apache.felix.dependencymanager";
+ * component(comp -> comp
+ * .impl(MyComponent.class)
+ * .withBundle(b -> b.mask(Bundle.ACTIVE).filter("(Bundle-SymbolicName=" + BSN + ")").cb(MyComponent::add, MyComponent::remove)));
+ *
+ * }
+ * }
+ * } </pre>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface BundleDependencyBuilder extends DependencyBuilder<BundleDependency> {
+ /**
+ * Enables auto configuration for this dependency. This means the component implementation (composition) will be
+ * injected with this bundle dependency automatically.
+ *
+ * @param autoConfig <code>true</code> to enable auto configuration
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder autoConfig(boolean autoConfig);
+
+ /**
+ * Enables auto configuration for this dependency. This means the component implementation (composition) will be
+ * injected with this bundle dependency automatically.
+ *
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder autoConfig();
+
+ /**
+ * Sets the dependency to be required. By default, the dependency is required.
+ *
+ * @param required <code>true</code> if this bundle dependency is required (true by default).
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder required(boolean required);
+
+ /**
+ * Sets the dependency to be required.
+ *
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder required();
+
+ /**
+ * Sets the bundle to depend on directly.
+ *
+ * @param bundle the bundle to depend on
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder bundle(Bundle bundle);
+
+ /**
+ * Sets the filter condition to depend on. Filters are matched against the full manifest of a bundle.
+ *
+ * @param filter the filter condition
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder filter(String filter);
+
+ /**
+ * Sets the bundle state mask to depend on. The OSGi BundleTracker explains this mask in more detail, but
+ * it is basically a mask with flags for each potential state a bundle can be in.
+ *
+ * @param mask the mask to use
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder mask(int mask);
+
+ /**
+ * Sets property propagation. If set to <code>true</code> any bundle manifest properties will be added
+ * to the service properties of the component that has this dependency (if it registers as a service).
+ *
+ * @param propagate <code>true</code> to propagate the bundle manifest properties
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder propagate(boolean propagate);
+
+ /**
+ * Sets property propagation. any bundle manifest properties will be added
+ * to the service properties of the component that has this dependency (if it registers as a service).
+ *
+ * @return the bundle dependency builder
+ */
+ public BundleDependencyBuilder propagate();
+
+ /**
+ * Sets an Object instance and a callback method used to propagate some properties to the provided service properties.
+ * The method will be invoked on the specified object instance and must have one of the following signatures:
+ * <ul><li>Dictionary callback(ServiceReference, Object service)
+ * <li>Dictionary callback(ServiceReference)
+ * </ul>
+ * @param instance the Object instance which is used to retrieve propagated service properties
+ * @param method the method to invoke for retrieving the properties to be propagated to the service properties.
+ * @return this service dependency. builder
+ */
+ public BundleDependencyBuilder propagate(Object instance, String method);
+
+ /**
+ * Sets an Object instance and a callback method used to propagate some properties to the provided service properties.
+ * The method will be invoked on the specified object instance and must have one of the following signatures:
+ * <ul><li>Dictionary callback(ServiceReference, Object service)
+ * <li>Dictionary callback(ServiceReference)
+ * </ul>
+ * @param instance the Object instance which is used to retrieve propagated service properties
+ * @return this service dependency. builder
+ */
+ public BundleDependencyBuilder propagate(Supplier<Dictionary<?, ?>> instance);
+
+ /**
+ * Sets some <code>callback</code> methods to invoke on the component instance(s). When a bundle state matches the bundle
+ * filter, then the bundle is injected using the specified callback methods. When you specify one callback, it stands for the "add" callback.
+ * When you specify two callbacks, the first one corresponds to the "add" callback, and the second one to the "remove" callback. When you specify three
+ * callbacks, the first one stands for the "add" callback, the second one for the "change" callback, and the third one for the "remove" callback.
+ *
+ * @param callbacks a list of callbacks (1 param: "add", 2 params: "add"/remove", 3 params: "add"/"change"/"remove" callbacks).
+ * @return this builder
+ */
+ BundleDependencyBuilder cb(String ... callbacks);
+
+ /**
+ * Sets some <code>callback instance</code> methods to invoke on a given Object instance. When a bundle state matches the bundle
+ * filter, then the bundle is injected using the specified callback methods. When you specify one callback, it stands for the "add" callback.
+ * When you specify two callbacks, the first one corresponds to the "add" callback, and the second one to the "remove" callback.
+ * When you specify three callbacks, the first one stands for the "add" callback, the second one for the "change" callback, and the third one for
+ * the "remove" callback.
+ *
+ * @param callbackInstance the Object instance where the callbacks are invoked on
+ * @param callbacks a list of callbacks (1 param: "add", 2 params: "add/remove", 3 params: "add/change/remove" callbacks).
+ * @return this builder
+ */
+ BundleDependencyBuilder cb(Object callbackInstance, String ... callbacks);
+
+ /**
+ * Sets a <code>callback</code> method reference which is invoked when a bundle is added.
+ * The method reference must point to a Component implementation class method, and take as argument a Bundle.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ <T> BundleDependencyBuilder cb(CbTypeBundle<T> add);
+
+ /**
+ * Sets some <code>callback</code> method references which are invoked when a bundle is added, or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Bundle.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleDependencyBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> remove);
+
+ /**
+ * Sets some <code>callback</code> method references which are invoked when a bundle is added, changed or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Bundle.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleDependencyBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> change, CbTypeBundle<T> remove);
+
+ /**
+ * Sets a <code>callback</code> method reference which is invoked when a bundle is added.
+ * The method reference must point to a Component implementation class method, and take as argument a Component and a Bundle.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ <T> BundleDependencyBuilder cb(CbTypeComponentBundle<T> add);
+
+ /**
+ * Sets some <code>callback</code> method references which are invoked when a bundle is added, or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Component and a Bundle.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleDependencyBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> remove);
+
+ /**
+ * Sets some <code>callback</code> method references which are invoked when a bundle is added, changed or removed.
+ * The method references must point to a Component implementation class method, and take as argument a Component and a Bundle.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ <T> BundleDependencyBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> change, CbTypeComponentBundle<T> remove);
+
+ /**
+ * Sets a <code>callback instance</code> method reference which is invoked when a bundle is added.
+ * The method reference must point to an Object instance method, and takes as argument a Bundle parameter.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ BundleDependencyBuilder cbi(CbBundle add);
+
+ /**
+ * Sets some <code>callback instance</code> method references which are invoked when a bundle is added or removed.
+ * The method references must point to an Object instance method, and take as argument a Bundle parameter.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleDependencyBuilder cbi(CbBundle add, CbBundle remove);
+
+ /**
+ * Sets some <code>callback instance</code> method references which are invoked when a bundle is added, changed or removed.
+ * The method references must point to an Object instance method, and take as argument a Bundle parameter.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleDependencyBuilder cbi(CbBundle add, CbBundle change, CbBundle remove);
+
+ /**
+ * Sets a <code>callback instance</code> method reference which is invoked when a bundle is added.
+ * The method reference must point to an Object instance method, and takes as arguments a Component and a Bundle.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @return this builder
+ */
+ BundleDependencyBuilder cbi(CbComponentBundle add);
+
+ /**
+ * Sets some <code>callback instance</code> method references which are invoked when a bundle is added or removed.
+ * The method references must point to an Object instance method, and take as argument a Component and a Bundle.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleDependencyBuilder cbi(CbComponentBundle add, CbComponentBundle remove);
+
+ /**
+ * Sets some <code>callback instance</code> method references which are invoked when a bundle is added, changed or removed.
+ * The method references must point to an Object instance method, and take as argument a Component and a Bundle.
+ *
+ * @param add the method reference invoked when a bundle is added.
+ * @param change the method reference invoked when a bundle has changed.
+ * @param remove the method reference invoked when a bundle is removed.
+ * @return this builder
+ */
+ BundleDependencyBuilder cbi(CbComponentBundle add, CbComponentBundle change, CbComponentBundle remove);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ComponentBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ComponentBuilder.java
new file mode 100644
index 0000000..8ac2366
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ComponentBuilder.java
@@ -0,0 +1,791 @@
+package org.apache.felix.dm.lambda;
+
+import java.util.Dictionary;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.lambda.callbacks.CbComponent;
+import org.apache.felix.dm.lambda.callbacks.CbConsumer;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponent;
+
+/**
+ * Builds a Dependency Manager Component. Components are the main building blocks for OSGi applications.
+ * They can publish themselves as a service, and they can have dependencies.
+ * These dependencies will influence their life cycle as component will only be activated when all
+ * required dependencies are available.
+ *
+ * <p> This interface is also the base interface for extended components like aspects, adapters, etc ...
+ *
+ * <p> Example of a component that depends on a ConfigurationAdmin service. The dependency is injected by reflection
+ * on a class field which type matches the ConfigurationAdmin interface:
+ *
+ * <pre>{@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp.impl(Configurator.class).withSrv(ConfigurationAdmin.class));
+ * }
+ * }
+ * } </pre>
+ *
+ * @param <B> the type of a builder that may extends this builder interface (aspect/adapter).
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ComponentBuilder<B extends ComponentBuilder<B>> {
+ /**
+ * Configures the component implementation. Can be a class name, or a component implementation object.
+ *
+ * @param impl the component implementation (a class, or an Object).
+ * @return this builder
+ */
+ B impl(Object impl);
+
+ /**
+ * Sets the factory to use to create the implementation. You can specify both the factory class and method to invoke. The method should return the implementation,
+ * and can use any method to create it. Actually, this can be used together with setComposition to create a composition of instances that work together to implement
+ * a component. The factory itself can also be instantiated lazily by not specifying an instance, but a Class.
+ *
+ * @param factory the factory instance, or the factory class.
+ * @param createMethod the create method called on the factory in order to instantiate the component instance.
+ * @return this builder
+ */
+ B factory(Object factory, String createMethod);
+
+ /**
+ * Configures a factory that can be used to create this component implementation.
+ * Example:
+ *
+ * <pre> {@code
+ * factory(ComponentImpl::new)", or "factory(() -> new ComponentImpl())
+ * }</pre>
+ *
+ * @param create the factory used to create the component implementation.
+ * @return this builder
+ */
+ B factory(Supplier<?> create);
+
+ /**
+ * Configures a factory used to create this component implementation using a Factory object and a method in the Factory object.
+ * Example:
+ *
+ * <pre> {@code
+ * factory(Factory::new, Factory::create)
+ * }</pre>
+ *
+ * @param <U> the type of the factory returned by the supplier
+ * @param <V> the type of the object that is returned by the factory create method.
+ * @param factory the function used to create the Factory itself
+ * @param create the method reference on the Factory method that is used to create the Component implementation
+ * @return this builder
+ */
+ <U, V> B factory(Supplier<U> factory, Function<U, V> create);
+
+ /**
+ * Configures a factory used to create this component implementation using a Factory object and a "getComponent" factory method.
+ * the Factory method may then return multiple objects that will be part of this component implementation.
+ *
+ * Example:
+ *
+ * <pre> {@code
+ * CompositionManager mngr = new CompositionManager();
+ * ...
+ * factory(mngr::create, mngr::getComposition)
+ * }</pre>
+ *
+ * @param factory the supplier used to return the main component implementation instance
+ * @param getComposition the supplier that returns the list of instances that are part of the component implementation classes.
+ * @return this builder
+ */
+ B factory(Supplier<?> factory, Supplier<Object[]> getComposition);
+
+ /**
+ * Configures a factory that also returns a composition of objects for this component implemenation.
+ *
+ * Example:
+ *
+ * <pre> {@code
+ * factory(CompositionManager::new, CompositionManager::create, CompositionManager::getComposition).
+ * }</pre>
+ *
+ * Here, the CompositionManager will act as a factory (the create method will return the component implementation object), and the
+ * CompositionManager.getComposition() method will return all the objects that are also part of the component implementation.
+ *
+ * @param <U> the type of the object returned by the supplier factory
+ * @param factory the function used to create the Factory itself
+ * @param create the Factory method used to create the main component implementation object
+ * @param getComposition the Factory method used to return the list of objects that are also part of the component implementation.
+ * @return this builder
+ */
+ <U> B factory(Supplier<U> factory, Function<U, ?> create, Function<U, Object[]> getComposition);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ *
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @return this builder
+ */
+ B provides(Class<?> iface);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ *
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @param name a property name for the provided service
+ * @param value a property value for the provided service
+ * @param rest the rest of property name/value pairs.
+ * @return this builder.
+ */
+ B provides(Class<?> iface, String name, Object value, Object ... rest);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ * Warning: you can only use this method if you compile your application using the "-parameters" javac option.
+ *
+ * code example:
+ *
+ * <pre> {@code
+ * provides(MyService.class, property1 -> "value1", property2 -> 123);
+ * }</pre>
+ *
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @param properties a list of fluent service properties for the provided service. You can specify a list of lambda expression, each one implementing the
+ * {@link FluentProperties} interface that allows to define a property name using a lambda parameter.
+ * @return this builder.
+ */
+ B provides(Class<?> iface, FluentProperties ... properties);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @param properties the properties for the provided service
+ * @return this builder.
+ */
+ B provides(Class<?> iface, Dictionary<?,?> properties);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ *
+ * @param ifaces list of services provided by the component.
+ * @return this builder.
+ */
+ B provides(Class<?>[] ifaces);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ *
+ * @param ifaces the public interfaces to register in the OSGI service registry.
+ * @param name a property name for the provided service
+ * @param value a property value for the provided service
+ * @param rest the rest of property name/value pairs.
+ * @return this builder.
+ */
+ B provides(Class<?>[] ifaces, String name, Object value, Object ... rest);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ * Warning: you can only use this method if you compile your application using the "-parameters" javac option.
+ * code example:
+ *
+ * <pre> {@code
+ * provides(new Class[] { MyService.class, MyService2.class }, property1 -> "value1", property2 -> 123);
+ * }</pre>
+ *
+ * @param ifaces the public interfaces to register in the OSGI service registry.
+ * @param properties a list of fluent service properties for the provided service. You can specify a list of lambda expression, each one implementing the
+ * {@link FluentProperties} interface that allows to define a property name using a lambda parameter.
+ * @return this builder.
+ */
+ B provides(Class<?>[] ifaces, FluentProperties ... properties);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ * @param ifaces the public interfaces to register in the OSGI service registry.
+ * @param properties the properties for the provided service
+ * @return this builder.
+ */
+ B provides(Class<?>[] ifaces, Dictionary<?,?> properties);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ *
+ * @param iface the service provided by this component.
+ * @return this builder.
+ */
+ B provides(String iface);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ *
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @param name a property name for the provided service
+ * @param value a property value for the provided service
+ * @param rest the rest of property name/value pairs.
+ * @return this builder.
+ */
+ B provides(String iface, String name, Object value, Object ... rest);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ * Warning: you can only use this method if you compile your application using the "-parameters" javac option.
+ * code example:
+ *
+ * <pre> {@code
+ * provides(MyService.class, property1 -> "value1", property2 -> 123);
+ * }</pre>
+ *
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @param properties a list of fluent service properties for the provided service. You can specify a list of lambda expression, each one implementing the
+ * {@link FluentProperties} interface that allows to define a property name using a lambda parameter.
+ * @return this builder.
+ */
+ B provides(String iface, FluentProperties ... properties);
+
+ /**
+ * Sets the public interface under which this component should be registered in the OSGi service registry.
+ * @param iface the public interfaces to register in the OSGI service registry.
+ * @param properties the properties for the provided service
+ * @return this builder.
+ */
+ B provides(String iface, Dictionary<?,?> properties);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ *
+ * @param ifaces the list of services provided by the component.
+ * @return this builder.
+ */
+ B provides(String[] ifaces);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ *
+ * @param ifaces the public interfaces to register in the OSGI service registry.
+ * @param name a property name for the provided service
+ * @param value a property value for the provided service
+ * @param rest the rest of property name/value pairs.
+ * @return this builder.
+ */
+ B provides(String[] ifaces, String name, Object value, Object ... rest);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ * Warning: you can only use this method if you compile your application using the "-parameters" javac option.
+ *
+ * code example:
+ * <pre> {@code
+ * provides(new Class[] { MyService.class, MyService2.class }, property1 -> "value1", property2 -> 123);
+ * }</pre>
+ *
+ * @param ifaces the public interfaces to register in the OSGI service registry.
+ * @param properties a list of fluent service properties for the provided service. You can specify a list of lambda expression, each one implementing the
+ * {@link FluentProperties} interface that allows to define a property name using a lambda parameter.
+ * @return this builder.
+ */
+ B provides(String[] ifaces, FluentProperties ... properties);
+
+ /**
+ * Sets the public interfaces under which this component should be registered in the OSGi service registry.
+ * @param ifaces the public interfaces to register in the OSGI service registry.
+ * @param properties the properties for the provided service
+ * @return this builder.
+ */
+ B provides(String[] ifaces, Dictionary<?,?> properties);
+
+ /**
+ * Sets the component's service properties
+ * @param properties the component's service properties
+ * @return this builder
+ */
+ B properties(Dictionary<?,?> properties);
+
+ /**
+ * Sets the components's service properties using varargs. The number of parameters must be even, representing a list of pair property key-value.
+ *
+ * <pre> {@code
+ * Example: properties("param1", "value1", "service.ranking", 3)
+ * }</pre>
+ *
+ * @param name the first property name
+ * @param value the first property value
+ * @param rest the rest of properties key/value pairs.
+ * @return this builder
+ */
+ B properties(String name, Object value, Object ... rest);
+
+ /**
+ * Sets the components's service properties using List of lamda properties.
+ *
+ * Example:
+ *
+ * <pre> {@code
+ * properties(param1 -> "value1, param2 -> 2);
+ * }</pre>
+ *
+ * When you use this method, you must compile your source code using the "-parameters" option, and the "arg0" parameter
+ * name is now allowed.
+ *
+ * @param properties the fluent properties
+ * @return this builder
+ */
+ B properties(FluentProperties ... properties);
+
+ /**
+ * Adds a required/autoconfig service dependency.
+ *
+ * @param service the service dependency filter
+ * @param filter the service filter
+ * @return this builder
+ */
+ B withSrv(Class<?> service, String filter);
+
+ /**
+ * Adds in one shot multiple required/autoconfig service dependencies.
+ * @param services the dependencies that are required and that will be injected in any field with the same dependency type.
+ * @return this builder
+ */
+ B withSrv(Class<?> ... services);
+
+ /**
+ * Adds a service dependency built using a Consumer lambda that is provided with a ServiceDependencyBuilder.
+ *
+ * @param <U> the type of the dependency service
+ * @param service the service
+ * @param consumer the lambda for building the service dependency
+ * @return this builder.
+ */
+ <U> B withSrv(Class<U> service, Consumer<ServiceDependencyBuilder<U>> consumer);
+
+ /**
+ * Adds a configuration dependency.
+ * @param consumer the lambda used to build the configuration dependency.
+ * @return this builder.
+ */
+ B withCnf(Consumer<ConfigurationDependencyBuilder> consumer);
+
+ /**
+ * Adds multiple configuration dependencies in one single call. All configurations are injected by default in the "updated" callback.
+ * @param pids list of configuration pids.
+ * @return this builder
+ */
+ @SuppressWarnings("unchecked")
+ default B withCnf(String ... pids) {
+ Stream.of(pids).forEach(pid -> withCnf(cnf -> cnf.pid(pid)));
+ return (B) this;
+ }
+
+ /**
+ * Adds multiple configuration dependencies in one single call.
+ * @param pids list of configuration pids
+ * @return this builder
+ */
+ @SuppressWarnings("unchecked")
+ default B withCnf(Class<?> ... pids) {
+ Stream.of(pids).forEach(pid -> withCnf(cnf -> cnf.pid(pid)));
+ return (B) this;
+ }
+
+ /**
+ * Adds a bundle dependency.
+ * @param consumer the lambda used to build the bundle dependency.
+ * @return this builder.
+ */
+ B withBundle(Consumer<BundleDependencyBuilder> consumer);
+
+ /**
+ * Adds a CompletableFuture dependency.
+ *
+ * @param <U> the type of the result of the CompletableFuture.
+ * @param future a CompletableFuture on which the dependency will wait for
+ * @param consumer the builder used to build the dependency
+ * @return this builder.
+ */
+ <U> B withFuture(CompletableFuture<U> future, Consumer<FutureDependencyBuilder<U>> consumer);
+
+ /**
+ * Sets the name of the method used as the "init" callback. This method, when found, is
+ * invoked as part of the life cycle management of the component implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The dependency manager will look for a method of this name with the following signatures,
+ * in this order:
+ * <ol>
+ * <li>method(Component component)</li>
+ * <li>method()</li>
+ * </ol>
+ *
+ * @param callback the callback name
+ * @return this builder.
+ */
+ B init(String callback);
+
+ /**
+ * Sets the name of the method used as the "start" callback. This method, when found, is
+ * invoked as part of the life cycle management of the component implementation. The
+ * dependency manager will look for a method of this name with the following signatures,
+ * in this order:
+ * <ol>
+ * <li>method(Component component)</li>
+ * <li>method()</li>
+ * </ol>
+ *
+ * @param callback the callback name
+ * @return this builder.
+ */
+ B start(String callback);
+
+ /**
+ * Sets the name of the method used as the "stop" callback. This method, when found, is
+ * invoked as part of the life cycle management of the component implementation. The
+ * dependency manager will look for a method of this name with the following signatures,
+ * in this order:
+ * <ol>
+ * <li>method(Component component)</li>
+ * <li>method()</li>
+ * </ol>
+ *
+ * @param callback the callback name
+ * @return this builder.
+ */
+ B stop(String callback);
+
+ /**
+ * Sets the name of the method used as the "destroy" callback. This method, when found, is
+ * invoked as part of the life cycle management of the component implementation. The
+ * dependency manager will look for a method of this name with the following signatures,
+ * in this order:
+ * <ol>
+ * <li>method(Component component)</li>
+ * <li>method()</li>
+ * </ol>
+ *
+ * @param callback the callback name
+ * @return this builder.
+ */
+ B destroy(String callback);
+
+ /**
+ * Sets the name of the methods used as init callback that is invoked on a given Object instance.
+ * These methods, when found, are invoked on the specified instance as part of the life cycle management
+ * of the component implementation.
+ * <p>
+ * Specifying an instance means you can create a manager
+ * that will be invoked whenever the life cycle of a component changes and this manager
+ * can then decide how to expose this life cycle to the actual component, offering an
+ * important indirection when developing your own component models.
+ *
+ * @see #init(String)
+ * @param callbackInstance the instance the callback will be invoked on.
+ * @param callback the callback name
+ * @return this builder.
+ */
+ B init(Object callbackInstance, String callback);
+
+ /**
+ * Sets the name of the methods used as start callback that is invoked on a given Object instance.
+ * These methods, when found, are invoked on the specified instance as part of the life cycle management
+ * of the component implementation.
+ * <p>
+ * Specifying an instance means you can create a manager
+ * that will be invoked whenever the life cycle of a component changes and this manager
+ * can then decide how to expose this life cycle to the actual component, offering an
+ * important indirection when developing your own component models.
+ *
+ * @see #start(String)
+ * @param callbackInstance the instance the callback will be invoked on.
+ * @param callback the name of the start method
+ * @return this builder.
+ */
+ B start(Object callbackInstance, String callback);
+
+ /**
+ * Sets the name of the methods used as stop callback that is invoked on a given Object instance.
+ * These methods, when found, are invoked on the specified instance as part of the life cycle management
+ * of the component implementation.
+ * <p>
+ * Specifying an instance means you can create a manager
+ * that will be invoked whenever the life cycle of a component changes and this manager
+ * can then decide how to expose this life cycle to the actual component, offering an
+ * important indirection when developing your own component models.
+ *
+ * @see #stop(String)
+ * @param callbackInstance the instance the callback will be invoked on.
+ * @param callback the name of the stop method
+ * @return this builder.
+ */
+ B stop(Object callbackInstance, String callback);
+
+ /**
+ * Sets the name of the methods used as destroy callback that is invoked on a given Object instance.
+ * These methods, when found, are invoked on the specified instance as part of the life cycle management
+ * of the component implementation.
+ * <p>
+ * Specifying an instance means you can create a manager
+ * that will be invoked whenever the life cycle of a component changes and this manager
+ * can then decide how to expose this life cycle to the actual component, offering an
+ * important indirection when developing your own component models.
+ *
+ * @see #destroy(String)
+ * @param callbackInstance the instance the callback will be invoked on.
+ * @param callback the name of the destroy method
+ * @return this builder.
+ */
+ B destroy(Object callbackInstance, String callback);
+
+ /**
+ * Sets a method reference used as the "init" callback. This method reference must point to method from one
+ * of the component instance classes. It is invoked as part of the life cycle management of the component implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The method does not take any parameters.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes.
+ * @return this builder
+ */
+ <U> B init(CbConsumer<U> callback);
+
+ /**
+ * Sets a method reference used as the "start" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes.
+ * @return this builder.
+ */
+ <U> B start(CbConsumer<U> callback);
+
+ /**
+ * Sets a method reference used as the "stop" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes.
+ * @return this builder.
+ */
+ <U> B stop(CbConsumer<U> callback);
+
+ /**
+ * Sets a method reference used as the "destroy" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes.
+ * @return this builder.
+ */
+ <U> B destroy(CbConsumer<U> callback);
+
+ /**
+ * Sets a method reference used as the "init" callback. This method reference must point to method from one
+ * of the component instance classes. It is invoked as part of the life cycle management of the component implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The method takes as argument a Component parameter.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes. The method takes as argument a Component parameter.
+ * @return this builder
+ */
+ <U> B init(CbTypeComponent<U> callback);
+
+ /**
+ * Sets a method reference used as the "start" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method takes as argument a Component parameter.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes. The method takes as argument a Component parameter.
+ * @return this builder.
+ */
+ <U> B start(CbTypeComponent<U> callback);
+
+ /**
+ * Sets a method reference used as the "stop" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method takes as argument a Component parameter.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes. The method takes as argument a Component parameter.
+ * @return this builder.
+ */
+ <U> B stop(CbTypeComponent<U> callback);
+
+ /**
+ * Sets a method reference used as the "destroy" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method takes as argument a Component parameter.
+ *
+ * @param <U> the type of the component class on which the callback is invoked on.
+ * @param callback a method reference must point to method from one of the component instance classes. The method takes as argument a Component parameter.
+ * @return this builder.
+ */
+ <U> B destroy(CbTypeComponent<U> callback);
+
+ /**
+ * Sets an Object instance method reference used as the "init" callback. It is invoked as part of the life cycle management of the component
+ * implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The method does not take any parameters.
+ *
+ * @param callback an Object instance method reference. The method does not take any parameters.
+ * @return this builder
+ */
+ B initInstance(Runnable callback);
+
+ /**
+ * Sets an Object instance method reference used as the "start" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method does not take any parameters.
+ *
+ * @param callback an Object instance method reference. The method does not take any parameters.
+ * @return this builder.
+ */
+ B startInstance(Runnable callback);
+
+ /**
+ * Sets an Object instance method reference used as the "stop" callback. It is invoked as part of the life cycle management of the component
+ * implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The method does not take any parameters.
+ *
+ * @param callback an Object instance method reference. The method does not take any parameters.
+ * @return this builder
+ */
+ B stopInstance(Runnable callback);
+
+ /**
+ * Sets an Object instance method reference used as the "destroy" callback. It is invoked as part of the life cycle management of the component
+ * implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The method does not take any parameters.
+ *
+ * @param callback an Object instance method reference. The method does not take any parameters.
+ * @return this builder
+ */
+ B destroyInstance(Runnable callback);
+
+ /**
+ * Sets an Object instance method reference used as the "init" callback. It is invoked as part of the life cycle management of the component
+ * implementation.
+ * This method is useful because when it is invoked, all required dependencies defines in the Activator
+ * are already injected, and you can then add more extra dependencies from the init() method.
+ * And once all extra dependencies will be available and injected, then the "start" callback will be invoked.
+ * The method takes as argument a Component parameter.
+ *
+ * @param callback an Object instance method reference.
+ * @return this builder
+ */
+ B initInstance(CbComponent callback);
+
+ /**
+ * Sets an Object instance method reference used as the "start" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method takes as argument a Component parameter.
+ *
+ * @param callback an Object instance method reference. The method takes as argument a Component parameter.
+ * @return this builder.
+ */
+ B startInstance(CbComponent callback);
+
+ /**
+ * Sets an Object instance method reference used as the "stop" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method takes as argument a Component parameter.
+ *
+ * @param callback an Object instance method reference. The method takes as argument a Component parameter.
+ * @return this builder.
+ */
+ B stopInstance(CbComponent callback);
+
+ /**
+ * Sets an Object instance method reference used as the "destroy" callback. This method reference must point to method from one
+ * of the component instance classes. This method is invoked as part of the life cycle management of the component implementation.
+ * The method takes as argument a Component parameter.
+ *
+ * @param callback an Object instance method reference. The method takes as argument a Component parameter.
+ * @return this builder.
+ */
+ B destroyInstance(CbComponent callback);
+
+ /**
+ * Configures OSGi object (BundleContext, Component, etc ...) that will be injected in any field having the same OSGi object type.
+ * @param clazz the OSGi object type (BundleContext, Component, DependencyManager).
+ * @param autoConfig true if the OSGi object has to be injected, false if not
+ * @return this builder
+ */
+ B autoConfig(Class<?> clazz, boolean autoConfig);
+
+ /**
+ * Configures OSGi object (BundleContext, Component, etc ...) that will be injected in a given field.
+ * @param clazz the OSGi object type (BundleContext, Component, DependencyManager).
+ * @param field the field that will be injected with the OSGI object
+ * @return this builder
+ */
+ B autoConfig(Class<?> clazz, String field);
+
+ /**
+ * Activates debug mode
+ * @param label the debug label
+ * @return this builder
+ */
+ B debug(String label);
+
+ /**
+ * Automatically adds this component to its DependencyManager object. When a lambda builds a Component using this builder, by default
+ * the built component is auto added to its DependencyManager object, unless you invoke autoAdd(false).
+ *
+ * @param autoAdd true for automatically adding this component to the DependencyManager object, false if not
+ * @return this builder
+ */
+ B autoAdd(boolean autoAdd);
+
+ /**
+ * Sets the method to invoke on the service implementation to get back all
+ * instances that are part of a composition and need dependencies injected.
+ * All of them will be searched for any of the dependencies. The method that
+ * is invoked must return an <code>Object[]</code>.
+ *
+ * @param getCompositionMethod the method to invoke
+ * @return this builder
+ */
+ B composition(String getCompositionMethod);
+
+ /**
+ * Sets the instance and method to invoke to get back all instances that
+ * are part of a composition and need dependencies injected. All of them
+ * will be searched for any of the dependencies. The method that is
+ * invoked must return an <code>Object[]</code>.
+ *
+ * @param instance the instance that has the method
+ * @param getCompositionMethod the method to invoke
+ * @return this builder
+ */
+ B composition(Object instance, String getCompositionMethod);
+
+ /**
+ * Sets a java8 method reference to a Supplier that returns all instances that are part of a composition and need dependencies injected.
+ * All of them will be searched for any of the dependencies. The method that
+ * is invoked must return an <code>Object[]</code>.
+ *
+ * @param getCompositionMethod the method to invoke
+ * @return this builder
+ */
+ B composition(Supplier<Object[]> getCompositionMethod);
+
+ /**
+ * Builds the real DependencyManager Component.
+ * @return the real DependencyManager Component.
+ */
+ Component build();
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java
new file mode 100644
index 0000000..c91a7fd
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ConfigurationDependencyBuilder.java
@@ -0,0 +1,129 @@
+package org.apache.felix.dm.lambda;
+
+import org.apache.felix.dm.ConfigurationDependency;
+import org.apache.felix.dm.lambda.callbacks.CbComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeDictionary;
+
+/**
+ * Builds a Dependency Manager Configuration Dependency.
+ * By default, the updated callback is "updated", like in original DM API.
+ *
+ * <p> Code example with a component that defines a Configuration Dependency. the ServiceImpl modified method
+ * callback is declared using a method reference (see the "cb(ServiceImpl::modified)" code):
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp
+ * .impl(ServiceImpl.class)
+ * .withConf(conf -> conf.pid(ServiceConsumer.class).cb(ServiceImpl::modified)));
+ * }
+ * }
+ * }</pre>
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ConfigurationDependencyBuilder extends DependencyBuilder<ConfigurationDependency> {
+ /**
+ * Sets the pid for this configuration dependency.
+ *
+ * @param pid the configuration dependendency pid.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder pid(String pid);
+
+ /**
+ * Sets the class which fqdn represents the pid for this configuration dependency. Usually, this class can optionally be annotated with metatypes bnd annotations.
+ *
+ * @param pidClass the class which fqdn represents the pid for this configuration dependency.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder pid(Class<?> pidClass);
+
+ /**
+ * Sets propagation of the configuration properties to the service properties (false by default).
+ * All public configuration properties (not starting with a dot) will be propagated to the component service properties.
+ *
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder propagate();
+
+ /**
+ * Sets propagation of the configuration properties to the service properties (false by default).
+ *
+ * @param propagate true if all public configuration properties (not starting with a dot) must be propagated to the component service properties (false by default)
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder propagate(boolean propagate);
+
+ /**
+ * Configures whether or not the component instance should be instantiated at the time the updated callback is invoked.
+ * By default, when the callback is applied on an external object instance, the component is not instantiated, but in this case
+ * you can force the creation of the component instances by calling this method.
+ *
+ * @param needsInstance true if the component instance should be instantiated at the time the updated callback is invoked on an external object instance.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder needsInstance(boolean needsInstance);
+
+ /**
+ * Sets a <code>callback</code> to call on the component instance(s) when the configuration is updated.
+ *
+ * @param updateMethod the callback to call on the component instance(s) when the configuration is updated.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder cb(String updateMethod);
+
+ /**
+ * Sets a <code>callback instance</code> to call on a given object instance when the configuration is updated.
+ * When the updated method is invoked, the Component implementation has not yet been instantiated, unless you have called
+ * the @link {@link #needsInstance(boolean)} method with "true".
+ *
+ * @param callbackInstance the object instance on which the updatedMethod is invoked
+ * @param updateMethod the callback to call on the callbackInstance when the configuration is updated.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder cbi(Object callbackInstance, String updateMethod);
+
+ /**
+ * Sets a <code>callback</code> method reference used to invoke an update method. The method reference must point to a method from one of the component
+ * implementation classes, and is invoked when the configuration is updated.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param callback the callback method reference which must point to a method from one of the component implementation classes. The method
+ * takes as argument a Dictionary.
+ * @return this builder
+ */
+ <T> ConfigurationDependencyBuilder cb(CbTypeDictionary<T> callback);
+
+ /**
+ * Sets the <code>callback</code> method reference used to invoke an update method. The method reference must point to a method from one of the
+ * component implementation classes, and is invoked when the configuration is updated.
+ *
+ * @param <T> the type of the component implementation class on which the callback is invoked on.
+ * @param callback the callback method reference used to invoke an update method on the component instance(s) when the configuration is updated.
+ * The method takes as argument a Component and a Dictionary.
+ * @return this builder
+ */
+ <T> ConfigurationDependencyBuilder cb(CbTypeComponentDictionary<T> callback);
+
+ /**
+ * Sets a <code>callback instance</code> method reference used to invoke the update method. The method reference must point to an Object instance
+ * method which takes as argument a Dictionary.
+ *
+ * @param updated a method reference that points to an Object instance method which takes as argument a Dictionary.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder cbi(CbDictionary updated);
+
+ /**
+ * Sets a <code>callback instance</code> method reference used to invoke the update method. The method reference must point to an Object instance method
+ * which takes as argument a Component and a Dictionary.
+ *
+ * @param updated a method reference that points to an Object instance method which takes as argument a Component and a Dictionary.
+ * @return this builder
+ */
+ ConfigurationDependencyBuilder cbi(CbComponentDictionary updated);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/DependencyBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/DependencyBuilder.java
new file mode 100644
index 0000000..cf0fb10
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/DependencyBuilder.java
@@ -0,0 +1,15 @@
+package org.apache.felix.dm.lambda;
+
+import org.apache.felix.dm.Dependency;
+
+/**
+ * Base class for all dependency builders
+ * @param <T> the dependency type.
+ */
+public interface DependencyBuilder<T extends Dependency> {
+ /**
+ * Builds a DependencyManager dependency.
+ * @return a real DependencyManager dependency
+ */
+ T build();
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/DependencyManagerActivator.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/DependencyManagerActivator.java
new file mode 100644
index 0000000..ae511e5
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/DependencyManagerActivator.java
@@ -0,0 +1,424 @@
+package org.apache.felix.dm.lambda;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.impl.BundleAdapterBuilderImpl;
+import org.apache.felix.dm.lambda.impl.BundleDependencyBuilderImpl;
+import org.apache.felix.dm.lambda.impl.CompletableFutureDependencyImpl;
+import org.apache.felix.dm.lambda.impl.ComponentBuilderImpl;
+import org.apache.felix.dm.lambda.impl.ConfigurationDependencyBuilderImpl;
+import org.apache.felix.dm.lambda.impl.FactoryPidAdapterBuilderImpl;
+import org.apache.felix.dm.lambda.impl.ServiceAdapterBuilderImpl;
+import org.apache.felix.dm.lambda.impl.ServiceAspectBuilderImpl;
+import org.apache.felix.dm.lambda.impl.ServiceDependencyBuilderImpl;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Defines a base for Activators in order to build DependencyManager Components using a java8 style.<p>
+ *
+ * Code example using auto configured fields:
+ *
+ * <pre> {@code
+ *
+ * import static org.apache.felix.dm.builder.lambda.DependencyActivatorBase.*;
+ *
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp
+ * .provides(Service.class, property -> "value")
+ * .impl(ServiceImpl.class)
+ * .withSrv(LogService.class, ConfigurationAdmni.class) // both services are required and injected in class fields with compatible types.
+ * }
+ * }
+ * }</pre>
+ *
+ * Code example using reflection callbacks:
+ *
+ * <pre> {@code
+ * import static org.apache.felix.dm.builder.lambda.DependencyActivatorBase.*;
+ *
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp
+ * .provides(Service.class, property -> "value")
+ * .impl(ServiceImpl.class)
+ * .withSrv(LogService.class, log -> log.cb("setLog"))
+ * .withSrv(ConfigurationAdmni.class, cm -> cm.cb("setConfigAdmin")))
+ * }
+ * }
+ * }</pre>
+ *
+ * Code example using method references:
+ *
+ * <pre> {@code
+ * import static org.apache.felix.dm.lambda.DependencyActivatorBase.*;
+ *
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp
+ * .provides(Service.class, property -> "value")
+ * .impl(ServiceImpl.class)
+ * .withSrv(LogService.class, log -> log.cb(ServiceImpl::setLog))
+ * .withSrv(ConfigurationAdmni.class, cm -> cm.cb(ServiceImpl::setConfigAdmin)))
+ * }
+ * }
+ * }</pre>
+ */
+public abstract class DependencyManagerActivator implements BundleActivator {
+ /**
+ * DependencyManager object used to create/register real DM Components that are built by this activator.
+ */
+ protected DependencyManager m_manager;
+
+ /**
+ * Bundle Context asociated to the activator bundle.
+ */
+ protected BundleContext m_ctx;
+
+ /**
+ * Our Activator is starting.
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ m_manager = new DependencyManager(context);
+ m_ctx = context;
+ activate();
+ }
+
+ /**
+ * Our Activator is stopped.
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ deactivate();
+ }
+
+ /**
+ * Sub classes must override this method in order to build some DM components.
+ * @throws Exception if the activation fails
+ */
+ protected abstract void activate() throws Exception;
+
+ /**
+ * Sub classes may override this method that is called when the Activator is stopped.
+ * @throws Exception if the deactivation fails
+ */
+ protected void deactivate() throws Exception {
+ }
+
+ /**
+ * Returns the DependencyManager used to create/managed DM Components.
+ *
+ * @return the DependencyManager associated to this Activator
+ */
+ protected DependencyManager getDependencyManager() {
+ return m_manager;
+ }
+
+ /**
+ * Returns the bundle context that is associated with this bundle.
+ *
+ * @return the bundle context
+ */
+ protected BundleContext getBundleContext() {
+ return m_ctx;
+ }
+
+ /**
+ * Creates a Component builder that can be used to create a DM Component.
+ * @return a Component builder that can be used to create a DM Component.
+ */
+ protected ComponentBuilder<?> component() {
+ return new ComponentBuilderImpl(m_manager);
+ }
+
+ /**
+ * Creates a service Aspect builder that can be used to create a DM Aspect Component.
+ *
+ * @param <T> the aspect service type
+ * @param aspectType the aspect service
+ * @return a service Aspect builder.
+ */
+ protected <T> ServiceAspectBuilder<T> aspect(Class<T> aspectType) {
+ ServiceAspectBuilderImpl<T> aspectBuilder = new ServiceAspectBuilderImpl<>(m_manager, aspectType);
+ return aspectBuilder;
+ }
+
+ /**
+ * Creates a service Adapter builder that can be used to create a DM Adapter Component.
+ *
+ * @param <T> the adapted service type.
+ * @param adaptee the adapted service
+ * @return a service Adapter builder.
+ */
+ protected <T> ServiceAdapterBuilder<T> adapter(Class<T> adaptee) {
+ ServiceAdapterBuilderImpl<T> adapterBuilder = new ServiceAdapterBuilderImpl<>(m_manager, adaptee);
+ return adapterBuilder;
+ }
+
+ /**
+ * Builds a DM Component using a Java8 style ComponentBuilder.
+ * @param consumer the lambda that will use the ComponentBuilder for building the DM component.
+ * The component is auto-added to the DependencyManager, unless the lambda calls the ComponentBuilder.autoAdd(false) method.
+ * @return a newly built DM component.
+ */
+ protected Component component(Consumer<ComponentBuilder<?>> consumer) {
+ return component(m_manager, consumer);
+ }
+
+ /**
+ * Builds a DM Aspect Component using a Java8 style AspectBuilder.
+ * The component is auto-added to the DependencyManager, unless the lambda calls the AspectBuilder.autoAdd(false) method.
+ *
+ * @param <T> the aspect service type
+ * @param aspect the aspect service
+ * @param consumer the lambda that will use the AspectBuilder for building the DM aspect component.
+ * @return the DM component build by the consumer of the aspect builder
+ */
+ protected <T> Component aspect(Class<T> aspect, Consumer<ServiceAspectBuilder<T>> consumer) {
+ return aspect(m_manager, aspect, consumer);
+ }
+
+ /**
+ * Builds a DM Adapter Component using a Java8 style AdapterBuilder.
+ * The component is auto-added to the DependencyManager, unless the lambda calls the AdapterBuilder.autoAdd(false) method.
+ *
+ * @param <T> the adapted service type
+ * @param adaptee the adapted service
+ * @param consumer the lambda that will use the AdapterBuilder for building the DM adapter component.
+ * @return a newly built DM component.
+ */
+ protected <T> Component adapter(Class<T> adaptee, Consumer<ServiceAdapterBuilder<T>> consumer) {
+ return adapter(m_manager, adaptee, consumer);
+ }
+
+ /**
+ * Builds a DM Factory Configuration Adapter Component using a Java8 style FactoryPidAdapterBuilder.
+ * The component is auto-added to the DependencyManager, unless the lambda calls the FactoryPidAdapterBuilder.autoAdd(false) method.
+ *
+ * @param consumer the lambda that will use the FactoryPidAdapterBuilder for building the DM factory configuration adapter component.
+ * @return a newly built DM component.
+ */
+ protected Component factoryPidAdapter(Consumer<FactoryPidAdapterBuilder> consumer) {
+ return factoryPidAdapter(m_manager, consumer);
+ }
+
+ /**
+ * Builds a DM Bundle Adapter Component.
+ * @param consumer the lambda used to build the actual bundle adapter.
+ * The component is auto-added to the DependencyManager, unless the lambda calls the BundleAdapter.autoAdd(false) method.
+ * @return a newly built DM component.
+ */
+ protected Component bundleAdapter(Consumer<BundleAdapterBuilder> consumer) {
+ return bundleAdapter(m_manager, consumer);
+ }
+
+ // These static methods can be used when building DM components outside of an activator.
+
+ /**
+ * Creates a Component builder that can be used to create a Component.
+ *
+ * @param dm the DependencyManager object used to create the component builder
+ * @return a Component builder that can be used to create a Component.
+ */
+ public static ComponentBuilder<?> component(DependencyManager dm) {
+ return new ComponentBuilderImpl(dm);
+ }
+
+ /**
+ * Creates a service Aspect builder that can be used to create an Aspect Component.
+ *
+ * @param <T> the aspect service type
+ * @param dm the DependencyManager object used to register the built component
+ * @param aspect the type of the aspect service
+ * @return a service Aspect builder that can be used to create an Aspect Component.
+ */
+ public static <T> ServiceAspectBuilder<T> aspect(DependencyManager dm, Class<T> aspect) {
+ ServiceAspectBuilderImpl<T> aspectBuilder = new ServiceAspectBuilderImpl<>(dm, aspect);
+ return aspectBuilder;
+ }
+
+ /**
+ * Creates a service Adapter builder that can be used to create an Adapter Component.
+ *
+ * @param <T> the adapted service type
+ * @param dm the DependencyManager object used to register the built component
+ * @param adaptee the type of the adaptee service
+ * @return a service Adapter builder that can be used to create an Adapter Component.
+ */
+ public static <T> ServiceAdapterBuilder<T> adapter(DependencyManager dm, Class<T> adaptee) {
+ ServiceAdapterBuilderImpl<T> adapterBuilder = new ServiceAdapterBuilderImpl<>(dm, adaptee);
+ return adapterBuilder;
+ }
+
+ /**
+ * Creates a factory pid adapter that can be used to create a factory adapter Component.
+ * @param dm the DependencyManager object used to register the built component
+ * @return a factory pid adapter that can be used to create a factory adapter Component.
+ */
+ public static FactoryPidAdapterBuilder factoryPidAdapter(DependencyManager dm) {
+ return new FactoryPidAdapterBuilderImpl(dm);
+ }
+
+ /**
+ * Creates a bundle adapter builder that can be used to create a DM bundle adapter Component.
+ *
+ * @param dm the DependencyManager object used to create the bundle adapter builder.
+ * @return a bundle adapter builder that can be used to create a DM bundle adapter Component.
+ */
+ public static BundleAdapterBuilder bundleAdapter(DependencyManager dm) {
+ return new BundleAdapterBuilderImpl(dm);
+ }
+
+ /**
+ * Creates a DM ServiceDependency builder.
+ *
+ * @param <T> the service dependency type
+ * @param component the component on which you want to build a new service dependency using the returned builder
+ * @param service the service dependency type.
+ * @return a DM ServiceDependency builder.
+ */
+ public static <T> ServiceDependencyBuilder<T> serviceDependency(Component component, Class<T> service) {
+ return new ServiceDependencyBuilderImpl<>(component, service);
+ }
+
+ /**
+ * Creates a DM Configuration Dependency builder.
+ *
+ * @param component the component on which you want to build a new configuration dependency using the returned builder
+ * @return a DM Configuration Dependency builder.
+ */
+ public static ConfigurationDependencyBuilder confDependency(Component component) {
+ return new ConfigurationDependencyBuilderImpl(component);
+ }
+
+ /**
+ * Creates a DM Bundle Dependency builder.
+ *
+ * @param component the component on which you want to build a new bundle dependency using the returned builder
+ * @return a DM Configuration Dependency builder.
+ */
+ public static BundleDependencyBuilder bundleDependency(Component component) {
+ return new BundleDependencyBuilderImpl(component);
+ }
+
+ /**
+ * Creates a DM CompletableFuture Dependency builder.
+ *
+ * @param <F> the type of the CompletableFuture result.
+ * @param component the component on which you want to build a new completable future dependency using the returned builder.
+ * @param future the future the dependency built using the returned builder will depend on.
+ * @return a CompletableFuture dependency builder.
+ */
+ public static <F> FutureDependencyBuilder<F> futureDependency(Component component, CompletableFuture<F> future) {
+ return new CompletableFutureDependencyImpl<>(component, future);
+ }
+
+ /**
+ * Builds a component using a lambda and a component builder
+ * @param dm the DependencyManager where the component is auto-added (unless the component.autoAdd(false) is called)
+ * @param consumer a lambda that is called to build the component. When the lambda is called, it will be provided with a
+ * ComponentBuilder object that is used to build the actual DM component.
+ *
+ * @return the built DM component.
+ */
+ public static Component component(DependencyManager dm, Consumer<ComponentBuilder<?>> consumer) {
+ ComponentBuilder<?> componentBuilder = new ComponentBuilderImpl(dm);
+ consumer.accept(componentBuilder);
+ Component comp = componentBuilder.build();
+ if (((ComponentBuilderImpl) componentBuilder).isAutoAdd()) {
+ dm.add(comp);
+ }
+ return comp;
+ }
+
+ /**
+ * Update an existing component. Typically, this method can be used from a Component.init method, where more dependencies has to be added.
+ * @param comp an existing DM component
+ * @param consumer the lambda that will be used to update the component
+ */
+ public static void component(Component comp, Consumer<ComponentBuilder<?>> consumer) {
+ ComponentBuilder<?> componentBuilder = new ComponentBuilderImpl(comp, true /* update component */);
+ consumer.accept(componentBuilder);
+ componentBuilder.build();
+ }
+
+ /**
+ * Builds an aspect DM Component.
+ *
+ * @param <T> the aspect service type
+ * @param dm the DependencyManager object used to register the built component
+ * @param aspect the type of the aspect service
+ * @param consumer a lambda used to build the DM aspect component
+ * @return a new DM aspect component. The aspect component is auto-added into the dm object, unless the lambda calls
+ * the AspectBuilder.autoAdd(false) method.
+ */
+ public static <T> Component aspect(DependencyManager dm, Class<T> aspect, Consumer<ServiceAspectBuilder<T>> consumer) {
+ ServiceAspectBuilderImpl<T> aspectBuilder = new ServiceAspectBuilderImpl<>(dm, aspect);
+ consumer.accept(aspectBuilder);
+ Component comp = aspectBuilder.build();
+ if (aspectBuilder.isAutoAdd()) {
+ dm.add(comp);
+ }
+ return comp;
+ }
+
+ /**
+ * Builds an adapter DM Component.
+ *
+ * @param <T> the adapted service type
+ * @param dm the DependencyManager object used to register the built component
+ * @param adaptee the type of the adapted service
+ * @param consumer a lambda used to build the DM adapter component
+ * @return a new DM adapter component. The adapter component is auto-added into the dm object, unless the lambda calls
+ * the AspectBuilder.autoAdd(false) method is called.
+ */
+ public static <T> Component adapter(DependencyManager dm, Class<T> adaptee, Consumer<ServiceAdapterBuilder<T>> consumer) {
+ ServiceAdapterBuilderImpl<T> adapterBuilder = new ServiceAdapterBuilderImpl<>(dm, adaptee);
+ consumer.accept(adapterBuilder);
+ Component comp = adapterBuilder.build();
+ if (adapterBuilder.isAutoAdd()) {
+ dm.add(comp);
+ }
+ return comp;
+ }
+
+ /**
+ * Builds a bundle adapter DM Component.
+ *
+ * @param dm the DependencyManager object used to register the built component
+ * @param consumer a lambda used to build the bundle adapter component
+ * @return a new bundle adapter component. The adapter component is auto-added into the dm object, unless the lambda calls
+ * the AspectBuilder.autoAdd(false) method is called.
+ */
+ public static Component bundleAdapter(DependencyManager dm, Consumer<BundleAdapterBuilder> consumer) {
+ BundleAdapterBuilderImpl adapterBuilder = new BundleAdapterBuilderImpl(dm);
+ consumer.accept(adapterBuilder);
+ Component comp = adapterBuilder.build();
+ if (adapterBuilder.isAutoAdd()) {
+ dm.add(comp);
+ }
+ return comp;
+ }
+
+ /**
+ * Builds a DM factory configuration adapter.
+ * @param dm the DependencyManager object used to create DM components.
+ * @param consumer a lambda used to build the DM factory configuration adapter component
+ * @return a new DM factory configuration adapter component. The adapter component is auto-added into the dm object, unless the lambda calls
+ * the FactoryPidAdapterBuilder.autoAdd(false) method is called
+ */
+ public static Component factoryPidAdapter(DependencyManager dm, Consumer<FactoryPidAdapterBuilder> consumer) {
+ FactoryPidAdapterBuilderImpl factoryPidAdapter = new FactoryPidAdapterBuilderImpl(dm);
+ consumer.accept(factoryPidAdapter);
+ Component comp = factoryPidAdapter.build();
+ if (factoryPidAdapter.isAutoAdd()) {
+ dm.add(comp);
+ }
+ return comp;
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FactoryPidAdapterBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FactoryPidAdapterBuilder.java
new file mode 100644
index 0000000..909109c
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FactoryPidAdapterBuilder.java
@@ -0,0 +1,120 @@
+package org.apache.felix.dm.lambda;
+
+import org.apache.felix.dm.lambda.callbacks.CbComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeDictionary;
+
+/**
+ * Builds a Dependency Manager Factory Configuration Adapter Component. For each new Config Admin factory configuration matching the factoryPid,
+ * an adapter will be created based on the adapter implementation class. The adapter will be registered with the specified interface,
+ * and with the specified adapter service properties. Depending on the propagate parameter, every public factory configuration properties
+ * (which don't start with ".") will be propagated along with the adapter service properties.
+ *
+ * <p> Example that defines a factory configuration adapter service for the "foo.bar" factory pid:
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * factoryPidAdapter(adapter -> adapter
+ * .impl(DictionaryImpl.class)
+ * .factoryPid("foo.bar").cb(ServiceImpl::updated)
+ * .propagate()
+ * .withSrv(LogService.class, log -> log.optional()));
+ * }
+ * }
+ * }</pre>
+ */
+public interface FactoryPidAdapterBuilder extends ComponentBuilder<FactoryPidAdapterBuilder> {
+ /**
+ * Specifies the factory pid used by the adapter.
+ * @param pid the factory pid.
+ * @return this builder
+ */
+ FactoryPidAdapterBuilder factoryPid(String pid);
+
+ /**
+ * Specifies a class name which fqdn represents the factory pid. Usually, this class can optionally be annotated with metatypes bnd annotations.
+ * @param pidClass the class that acts as the factory pid
+ * @return this builder
+ */
+ FactoryPidAdapterBuilder factoryPid(Class<?> pidClass);
+
+ /**
+ * Specifies if the public properties (not starting with a dot) should be propagated in the adapter service properties (false by default).
+ * @return this builder.
+ */
+ FactoryPidAdapterBuilder propagate();
+
+ /**
+ * Specifies if the public properties (not starting with a dot) should be propagated in the adapter service properties (false by default).
+ * @param propagate true if the public properties should be propagated in the adapter service properties (false by default).
+ * @return this builder.
+ */
+ FactoryPidAdapterBuilder propagate(boolean propagate);
+
+ /**
+ * Specifies a callback method that will be called on the component instances when the configuration is injected
+ * @param updateMethod the method to call on the component instances when the configuration is available ("updated" by default).
+ * The following method signatures are supported:
+ *
+ * <pre> {@code
+ * method(Dictionary properties)
+ * method(Component component, Dictionary properties)
+ * }</pre>
+ *
+ * @return this builder
+ */
+ FactoryPidAdapterBuilder cb(String updateMethod);
+
+ /**
+ * Specifies a callback instance method that will be called on a given object instance when the configuration is injected
+ * @param updateMethod the method to call on the given object instance when the configuration is available ("updated" by default).
+ * The following method signatures are supported:
+ *
+ * <pre> {@code
+ * method(Dictionary properties)
+ * method(Component component, Dictionary properties)
+ * }</pre>
+ *
+ * @param callbackInstance the Object instance on which the updated callback will be invoked.
+ * @return this builder
+ */
+ FactoryPidAdapterBuilder cb(Object callbackInstance, String updateMethod);
+
+ /**
+ * Specifies a callback method reference that will be called on one of the component classes when the configuration is injected.
+ *
+ * @param <U> the type of the component implementation class on which the callback is invoked on.
+ * @param callback the method to call on one of the component classes when the configuration is available.
+ * @return this builder
+ */
+ <U> FactoryPidAdapterBuilder cb(CbTypeDictionary<U> callback);
+
+ /**
+ * Specifies a callback method reference that will be called on one of the component classes when the configuration is injected
+ *
+ * @param <U> the type of the component implementation class on which the callback is invoked on.
+ * @param callback the reference to a method on one of the component classes. The method may takes as parameter a Component and a Dictionary.
+ * @return this builder
+ */
+ <U> FactoryPidAdapterBuilder cb(CbTypeComponentDictionary<U> callback);
+
+ /**
+ * Specifies a callback instance method reference that will be called on a given object instance when the configuration is injected
+ *
+ * @param callback the method to call on a given object instance when the configuration is available. The callback takes as argument a
+ * a Dictionary parameter.
+ * @return this builder
+ */
+ FactoryPidAdapterBuilder cbi(CbDictionary callback);
+
+ /**
+ * Specifies a callback instance method reference that will be called on a given object instance when the configuration is injected.
+ *
+ * @param callback the method to call on a given object instance when the configuration is available. The callback takes as argument a
+ * Dictionary parameter.
+ * @return this builder
+ */
+ FactoryPidAdapterBuilder cbi(CbComponentDictionary callback);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FluentProperties.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FluentProperties.java
new file mode 100644
index 0000000..7ee7724
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FluentProperties.java
@@ -0,0 +1,35 @@
+package org.apache.felix.dm.lambda;
+
+import org.apache.felix.dm.lambda.callbacks.SerializableLambda;
+
+/**
+ * Lambda allowing to define fluent service properties. Property names are deduces from the lambda parameter name.
+ *
+ * <p> Example of a component which provides fluent properties ("foo=bar"; "foo2=Integer(123)):
+ *
+ * <pre>{@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp.impl(MyComponentImpl.class).provides(MyService.class, foo->"bar", foo2 -> 123));
+ * }
+ * }
+ * }</pre>
+ *
+ * <b>Caution: Fluent properties requires the usage of the "-parameter" javac option.</b>
+ *
+ * Under eclipse, you can enable this option using:
+ *
+ * <pre>{@code
+ * Windows -> Preference -> Compiler -> Classfile Generation -> Store information about method parameters.
+ * }</pre>
+ */
+@FunctionalInterface
+public interface FluentProperties extends SerializableLambda {
+ /**
+ * Represents a fluent property
+ *
+ * @param name the property name. The parameter used by the lambda will be intropsected and will be used as the actual property name.
+ * @return the property value
+ */
+ public Object apply(String name);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FutureDependencyBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FutureDependencyBuilder.java
new file mode 100644
index 0000000..800e306
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/FutureDependencyBuilder.java
@@ -0,0 +1,129 @@
+package org.apache.felix.dm.lambda;
+
+import java.util.concurrent.Executor;
+
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.lambda.callbacks.CbFuture;
+import org.apache.felix.dm.lambda.callbacks.CbTypeFuture;
+
+/**
+ * Defines a builder for a CompletableFuture dependency.
+ * Using such dependency allows your component to wait for the completion of a given asynchronous task
+ * represented by a standard jdk <code>CompletableFuture</code> object.
+ *
+ * A FutureDependency is required and unblock the Component once the CompletableFuture result has completed.
+ *
+ * <h3>Usage Example</h3>
+ *
+ * <p> Here is an Activator that downloads a page from the web and injects the string result to a component.
+ * When the web page is downloaded, the result is injected in the MyComponent::setPage method and
+ * the component is then called in its "start" method:
+ *
+ * <pre>{@code
+ *
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * String url = "http://felix.apache.org/";
+ * CompletableFuture<String> page = CompletableFuture.supplyAsync(() -> downloadSite(url));
+ *
+ * // The component depends on a log service and on the content of the Felix site.
+ * // The lambda passed to the "withFuture" method configures the callback that is
+ * // invoked with the result of the CompletableFuture (the page content).
+ * component(comp -> comp
+ * .impl(MyComponent.class)
+ * .withService(LogService.class)
+ * .withFuture(page, result -> result.cb(MyComponent::setPage)));
+ * }
+ * }
+ *
+ * public class MyComponent {
+ * volatile LogService log; // injected.
+ *
+ * void setPage(String page) {
+ * // injected by the FutureDependency.
+ * }
+ *
+ * void start() {
+ * // all required dependencies injected.
+ * }
+ * }
+ *
+ * }</pre>
+ *
+ * @param <F> the type of the CompletableFuture result.
+ */
+public interface FutureDependencyBuilder<F> extends DependencyBuilder<Dependency> {
+ /**
+ * Sets the callback method name to invoke on the component instances, once the CompletableFuture has completed.
+ * @param callback the callback method name to invoke on the component instances, once the CompletableFuture on which we depend has completed.
+ * @return this dependency.
+ */
+ FutureDependencyBuilder<F> cb(String callback);
+
+ /**
+ * Sets the function to invoke when the future task has completed. The function is from one of the Component implementation classes, and it accepts the
+ * result of the completed future.
+ *
+ * @param <T> the type of the CompletableFuture result.
+ * @param callback the function to perform when the future task as completed.
+ * @return this dependency
+ */
+ <T> FutureDependencyBuilder<F> cb(CbTypeFuture<T, ? super F> callback);
+
+ /**
+ * Sets the function to invoke asynchronously when the future task has completed. The function is from one of the Component implementation classes,
+ * and it accepts the result of the completed future.
+ *
+ * @param <T> the type of the CompletableFuture result.
+ * @param callback the function to perform when the future task as completed.
+ * @param async true if the callback should be invoked asynchronously using the default jdk execution facility, false if not.
+ * @return this dependency
+ */
+ <T> FutureDependencyBuilder<F> cb(CbTypeFuture<T, ? super F> callback, boolean async);
+
+ /**
+ * Sets the function to invoke asynchronously when the future task has completed. The function is from one of the Component implementation classes,
+ * and it accepts the result of the completed future.
+ *
+ * @param <T> the type of the CompletableFuture result.
+ * @param callback the function to perform when the future task as completed.
+ * @param executor the executor used to schedule the callback.
+ * @return this dependency
+ */
+ <T> FutureDependencyBuilder<F> cb(CbTypeFuture<T, ? super F> callback, Executor executor);
+
+ /**
+ * Sets the callback instance method name to invoke on a given Object instance, once the CompletableFuture has completed.
+ * @param callbackInstance the object instance on which the callback must be invoked
+ * @param callback the callback method name to invoke on Object instance, once the CompletableFuture has completed.
+ * @return this dependency.
+ */
+ FutureDependencyBuilder<F> cbi(Object callbackInstance, String callback);
+
+ /**
+ * Sets the callback instance to invoke when the future task has completed. The callback is a Consumer instance which accepts the
+ * result of the completed future.
+ * @param callback a Consumer instance which accepts the result of the completed future.
+ * @return this dependency
+ */
+ FutureDependencyBuilder<F> cbi(CbFuture<? super F> callback);
+
+ /**
+ * Sets the callback instance to invoke when the future task has completed. The callback is a Consumer instance which accepts the
+ * result of the completed future.
+ *
+ * @param callback a Consumer instance which accepts the result of the completed future.
+ * @param async true if the callback should be invoked asynchronously using the default jdk execution facility, false if not.
+ * @return this dependency
+ */
+ FutureDependencyBuilder<F> cbi(CbFuture<? super F> callback, boolean async);
+
+ /**
+ * Sets the callback instance to invoke when the future task has completed. The callback is a Consumer instance which accepts the
+ * result of the completed future.
+ * @param callback the action to perform when the future task as completed.
+ * @param executor the executor to use for asynchronous execution of the callback.
+ * @return this dependency
+ */
+ FutureDependencyBuilder<F> cbi(CbFuture<? super F> callback, Executor executor);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceAdapterBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceAdapterBuilder.java
new file mode 100644
index 0000000..eef4890
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceAdapterBuilder.java
@@ -0,0 +1,59 @@
+package org.apache.felix.dm.lambda;
+
+/**
+ * Builds a Dependency Manager Service Adapter Component.
+ * The adapter will be applied to any service that matches the specified interface and filter. For each matching service an adapter will be created
+ * based on the adapter implementation class. The adapter will be registered with the specified interface and existing properties from the original
+ * service plus any extra properties you supply here.<p>
+ *
+ * Code example that adapts a "Device" service to an HttpServlet service. The adapter is created using a ServiceAdapterBuilder that is passed to the lambda.
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * adapter(Device.class, adapt -> adapt.impl(DeviceServlet.class).provides(HttpServlet.class).properties(alias -> "/device");
+ * }
+ * }}</pre>
+ *
+ * @param <T> the adaptee service
+ */
+public interface ServiceAdapterBuilder<T> extends ComponentBuilder<ServiceAdapterBuilder<T>>, ServiceCallbacksBuilder<T, ServiceAdapterBuilder<T>> {
+ /**
+ * Specifies the filter used to match a given adapted service.
+ *
+ * @param adapteeFilter the filter used to match a given adapted service
+ * @return this builder
+ */
+ ServiceAdapterBuilder<T> filter(String adapteeFilter);
+
+ /**
+ * Specifies whether or not the adapted service properties must be propagated to the adapter service (true by default).
+ *
+ * @param propagate true if the adapted service properties must be propagated to the adapter service (true by default).
+ * @return this builder
+ */
+ ServiceAdapterBuilder<T> propagate(boolean propagate);
+
+ /**
+ * Injects this adapted service in all fields matching the adapted service type.
+ *
+ * @return this builder
+ */
+ ServiceAdapterBuilder<T> autoConfig();
+
+ /**
+ * Configures whether or not the adapted service can be injected in all fields matching the adapted service type.
+ *
+ * @param autoConfig true if the adapted service can be injected in all fields matching the adapted service type
+ * @return this builder
+ */
+ ServiceAdapterBuilder<T> autoConfig(boolean autoConfig);
+
+ /**
+ * Injects this adapted service on the field matching the given name
+ *
+ * @param field the field name where the adapted service must be injected to.
+ * @return this builder
+ */
+ ServiceAdapterBuilder<T> autoConfig(String field);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceAspectBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceAspectBuilder.java
new file mode 100644
index 0000000..160975e
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceAspectBuilder.java
@@ -0,0 +1,72 @@
+package org.apache.felix.dm.lambda;
+
+/**
+ * Builds a Dependency Manager Aspect Component.
+ * The aspect will be applied to any service that matches the specified interface and filter (if any). For each matching service an aspect will be created based
+ * on the aspect implementation class.
+ * The aspect will be registered with the same interface and properties as the original service, plus any extra properties you supply here.
+ * Multiple Aspects of the same service are chained and ordered using aspect ranks.
+ *
+ * <p> Code example that provides a "LogService" aspect that performs spell-checking of each log message.
+ * The aspect decorates a LogService. The aspect also depends on an Dictionary service that is internally used to perform log spell checking.
+ * The LogService and Dictionary services are injected in the aspect implementation using reflection on class fields:
+ *
+ * <pre>{@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * aspect(LogService.class, asp -> asp.impl(SpellCheckLogAspect.class).rank(10).withSrv(Dictionary.class));
+ * }
+ * }} </pre>
+ *
+ * Same example, but using callbacks for injecting LogService and Dictionary services in the aspect implementation class:
+ *
+ * <pre>{@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * aspect(LogService.class, asp -> asp.impl(SpellCheckLogAspect.class).rank(10)
+ * .cb(SpellCheckLogAspect::setLogService)
+ * .withSrv(Dictionary.class, dict -> dict.cb(SpellCheckLogAspect::setDictionary)));
+ * }
+ * }} </pre>
+ *
+ * @param <T> the aspect service
+ */
+public interface ServiceAspectBuilder<T> extends ComponentBuilder<ServiceAspectBuilder<T>>, ServiceCallbacksBuilder<T, ServiceAspectBuilder<T>> {
+ /**
+ * Specifies the aspect service filter.
+ *
+ * @param filter the filter condition to use with the service interface the aspect will apply on
+ * @return this builder
+ */
+ ServiceAspectBuilder<T> filter(String filter);
+
+ /**
+ * Specifies the aspect ranking. Aspects of a given service are ordered by their ranking property.
+ *
+ * @param ranking the aspect ranking
+ * @return this builder
+ */
+ ServiceAspectBuilder<T> rank(int ranking);
+
+ /**
+ * Injects the aspect in all fields matching the aspect type.
+ * @return this builder
+ */
+ ServiceAspectBuilder<T> autoConfig();
+
+ /**
+ * Configures whether or not the aspect service can be injected in all fields matching the aspect type.
+ *
+ * @param autoConfig true if the aspect service can be injected in all fields matching the dependency type
+ * @return this builder
+ */
+ ServiceAspectBuilder<T> autoConfig(boolean autoConfig);
+
+ /**
+ * Injects the aspect service on the field with the given name.
+ *
+ * @param field the field name where the aspect service must be injected
+ * @return this builder
+ */
+ ServiceAspectBuilder<T> autoConfig(String field);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceCallbacksBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceCallbacksBuilder.java
new file mode 100644
index 0000000..d6190bc
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceCallbacksBuilder.java
@@ -0,0 +1,799 @@
+package org.apache.felix.dm.lambda;
+
+import org.apache.felix.dm.lambda.callbacks.CbComponent;
+import org.apache.felix.dm.lambda.callbacks.CbComponentRef;
+import org.apache.felix.dm.lambda.callbacks.CbComponentRefService;
+import org.apache.felix.dm.lambda.callbacks.CbComponentRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbComponentService;
+import org.apache.felix.dm.lambda.callbacks.CbComponentServiceService;
+import org.apache.felix.dm.lambda.callbacks.CbRef;
+import org.apache.felix.dm.lambda.callbacks.CbRefService;
+import org.apache.felix.dm.lambda.callbacks.CbRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbService;
+import org.apache.felix.dm.lambda.callbacks.CbServiceDict;
+import org.apache.felix.dm.lambda.callbacks.CbServiceMap;
+import org.apache.felix.dm.lambda.callbacks.CbServiceService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponent;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentRef;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentServiceService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeRef;
+import org.apache.felix.dm.lambda.callbacks.CbTypeRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeServiceDict;
+import org.apache.felix.dm.lambda.callbacks.CbTypeServiceMap;
+import org.apache.felix.dm.lambda.callbacks.CbTypeServiceService;
+
+/**
+ * Builds a service dependency callback (required by default).
+ *
+ * A Service may be injected in a bind-method of a component or an object instance using this builder.
+ * The builder supports the following kind of method signatures for bind methods:
+ *
+ * <pre> {@code
+ * method(S service)
+ * method(S service, Map<String, Object> serviceProperties)
+ * method(S service, Dictionary<String, Object> serviceProperties)
+ * method(ServiceReference<S> serviceRef, S service),
+ * method(ServiceReference<S> serviceRef)
+ * method(Component serviceComponent)
+ * method(Component serviceComponent, ServiceReference<S> serviceRef)
+ * method(Component serviceComponent, S service)
+ * method(Component serviceComponent, ServiceReference<S> serviceRef, S service)
+ * swapMethod(S oldService, S newService)
+ * swapMethod(ServiceReference<S> oldRef, S old, ServiceReference<S> newRef, S newService)
+ * swapMethod(Component component, S oldService, S newService)
+ * swapMethod(Component component, ServiceReference<S> oldRef, S old, ServiceReference<S> newRef, S newService)
+ * }</pre>
+ *
+ * The following families of callbacks are supported:
+ *
+ * <ul>
+ * <li> "cb(String ... callback)": stands for "callback" and specifies a list of callbacks from the component instances. When using one arg, it stands for the "add" callback.
+ * When using two args, it stands for "add/remove" callbacks. When using three args, it stands for "add/change/remove" callbacks. When using four args, it stands for "add/change/remove/swap" callbacks.
+ * <li> "cbi(Object callbackInstance, String ... callbacks)": stands for "callback instance" and specifies some callbacks on a given object instance.
+ * <li> "cb(lambda) ": stands for "callback" and specifies a method reference of a callback from a given component class.
+ * <li> "cbi(lambda)": stands for "callback instance" and specifies a method reference from a given object instance.
+ * <li> "sw(lambda)": stands for "swap callback" and specifies a method reference of a swap callback from a given component class.
+ * <li> "swi(lambda)": stands for "swap callback instance" and specifies a method reference of a swap callback from a given object instance.
+ * </ul>
+ *
+ * <p> Here is an example of a Component that defines a dependency of a LogService which is injected in the "bindLogService" method using a ServiceCallbacksBuilder:
+ * The withSrv(...)" declaration defines a method reference on the "ComponentImpl::bindLogService" method (using a lambda):
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp.impl(ComponentImpl.class).withSrv(LogService.class, log -> log.cb(ComponentImpl::bindLogService)));
+ * }
+ * }}</pre>
+ *
+ * <p> Same example, but we inject the dependency in an object instance that we already have in hand:
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * ComponentImpl impl = new ComponentImpl();
+ * component(comp -> comp.impl(impl).withSrv(LogService.class, log -> log.cbi(impl::bindLogService)));
+ * }
+ * }}</pre>
+ *
+ * <p> Here, we inject a service using method reflection (as it is the case in original DM api):
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * component(comp -> comp.impl(ComponentImpl::class).withSrv(LogService.class, log -> log.cb("bindLogService")));
+ * }
+ * }}</pre>
+ *
+ * <p> Same example, but we inject the dependency in an object instance that we already have in hand:
+ *
+ * <pre> {@code
+ * public class Activator extends DependencyManagerActivator {
+ * public void activate() throws Exception {
+ * ComponentImpl impl = new ComponentImpl();
+ * component(comp -> comp.impl(impl).withSrv(LogService.class, log -> log.cbi(impl, "bindLogService")));
+ * }
+ * }}</pre>
+ *
+ * @param <S> the service dependency type
+ * @param <B> the type of a sub interface that may extends this interface.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceCallbacksBuilder<S, B extends ServiceCallbacksBuilder<S, B>> {
+ /**
+ * Sets <code>callback</code> methods to invoke on the component instance(s). When a service matches the service
+ * filter, then the service is injected using the specified callback methods. When you specify one callback, it stands for the "add" callback.
+ * When you specify two callbacks, the first one corresponds to the "add" callback, and the second one to the "remove" callback. When you specify three
+ * callbacks, the first one stands for the "add" callback, the second one for the "change" callback, and the third one for the "remove" callback.
+ * When you specify four callbacks, it stands for "add"/"change"/"remove"/swap callbacks.
+ *
+ * The following method signature are supported:
+ * <pre>{@code
+ * method(S service)
+ * method(S service, Map<String, Object> serviceProperties)
+ * method(S service, Dictionary<String, Object> serviceProperties)
+ * method(ServiceReference<S> serviceRef, S service),
+ * method(ServiceReference<S> serviceRef)
+ * method(Component serviceComponent)
+ * method(Component serviceComponent, ServiceReference<S> serviceRef)
+ * method(Component serviceComponent, S service)
+ * method(Component serviceComponent, ServiceReference<S> serviceRef, S service)
+ * swapMethod(S oldService, S newService)
+ * swapMethod(ServiceReference<S> oldRef, S old, ServiceReference<S> newRef, S newService)
+ * swapMethod(Component component, S oldService, S newService)
+ * swapMethod(Component component, ServiceReference<S> oldRef, S old, ServiceReference<S> newRef, S newService)
+ * }</pre>
+ *
+ * @param callbacks a list of callbacks (1 param: "add", 2 params: "add"/remove", 3 params: "add"/"change"/"remove", 4 params: "add"/"change"/"remove"/"swap" callbacks).
+ * @return this builder
+ */
+ B cb(String ... callbacks);
+
+ /**
+ * Sets <code>callback instance</code> methods to invoke on a given Object instance. When a service matches the service
+ * filter, then the service is injected using the specified callback methods. When you specify one callback, it stands for the "add" callback.
+ * When you specify two callbacks, the first one corresponds to the "add" callback, and the second one to the "remove" callback. When you specify three
+ * callbacks, the first one stands for the "add" callback, the second one for the "change" callback, and the third one for the "remove" callback.
+ *
+ * @param callbackInstance the object on which the callback is invoked.
+ * @param callbacks a list of callbacks (1 param : "add", 2 params : "add"/remove", 3 params : "add"/"change"/"remove", 4 params : "add"/"change"/"remove"/"swap" callbacks).
+ * @see #cb(String...)
+ * @return this builder
+ */
+ B cbi(Object callbackInstance, String ... callbacks);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeService<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeService<T, S> add, CbTypeService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeService<T, S> add, CbTypeService<T, S> change, CbTypeService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service, and a properties map.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeServiceMap<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service, and a properties map.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeServiceMap<T, S> add, CbTypeServiceMap<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service, and a properties map.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeServiceMap<T, S> add, CbTypeServiceMap<T, S> change, CbTypeServiceMap<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service, and a properties dictionary.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeServiceDict<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service, and a properties dictionary.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeServiceDict<T, S> add, CbTypeServiceDict<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service, and a properties dictionary.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeServiceDict<T, S> add, CbTypeServiceDict<T, S> change, CbTypeServiceDict<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service reference, and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeRefService<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service reference, and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeRefService<T, S> add, CbTypeRefService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service reference, and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeRefService<T, S> add, CbTypeRefService<T, S> change, CbTypeRefService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service reference.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeRef<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service reference.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeRef<T, S> add, CbTypeRef<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the service reference.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeRef<T, S> add, CbTypeRef<T, S> change, CbTypeRef<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponent<T> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponent<T> add, CbTypeComponent<T> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponent<T> add, CbTypeComponent<T> change, CbTypeComponent<T> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, and the service reference.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentRef<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, and the service reference.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentRef<T, S> add, CbTypeComponentRef<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, and the service reference.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentRef<T, S> add, CbTypeComponentRef<T, S> change, CbTypeComponentRef<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentService<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentService<T, S> add, CbTypeComponentService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentService<T, S> add, CbTypeComponentService<T, S> change, CbTypeComponentService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, the service Reference and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentRefService<T, S> add);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, the service Reference and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentRefService<T, S> add, CbTypeComponentRefService<T, S> remove);
+
+ /**
+ * Sets a <code>callback</code> invoked when a service is added, changed, or removed.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the Component, the service Reference and the service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ <T> B cb(CbTypeComponentRefService<T, S> add, CbTypeComponentRefService<T, S> change, CbTypeComponentRefService<T, S> remove);
+
+ /**
+ * Sets a <code>swap callback(Service, Service)</code> invoked when a service is swapped.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the old service and the new replacing service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ <T> B sw(CbTypeServiceService<T, S> swap);
+
+ /**
+ * Sets a <code>swap callback(Component, Service, Service)</code> invoked when a service is swapped.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the component, the old service and the new replacing service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ <T> B sw(CbTypeComponentServiceService<T, S> swap);
+
+ /**
+ * Sets a <code>swap callback(ServiceReference, Service, ServiceReference, Service)</code> invoked when a service is swapped.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the old service reference, the old service, the new service reference, and
+ * the new service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ <T> B sw(CbTypeRefServiceRefService<T, S> swap);
+
+ /**
+ * Sets a swap <code>callback</code> invoked when a service is swapped.
+ * The method reference must point to a Component implementation class method. Callback argument(s): the component, the old service reference, the old service, the new service reference, and
+ * the new service.
+ *
+ * @param <T> the type of the component instance class on which the callback is invoked.
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ <T> B sw(CbTypeComponentRefServiceRefService<T, S> swap);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbService<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbService<S> add, CbService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbService<S> add, CbService<S> change, CbService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a service and a properties Map.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbServiceMap<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service and a properties Map.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbServiceMap<S> add, CbServiceMap<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service and a properties Map.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbServiceMap<S> add, CbServiceMap<S> change, CbServiceMap<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a service and a properties Dictionary.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbServiceDict<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service and a properties Dictionary.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbServiceDict<S> add, CbServiceDict<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service and a properties Dictionary.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbServiceDict<S> add, CbServiceDict<S> change, CbServiceDict<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a service reference and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbRefService<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service reference and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbRefService<S> add, CbRefService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service reference and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbRefService<S> add, CbRefService<S> change, CbRefService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a service reference.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbRef<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service reference.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbRef<S> add, CbRef<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a service reference.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbRef<S> add, CbRef<S> change, CbRef<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a Component.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbComponent add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponent add, CbComponent remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponent add, CbComponent change, CbComponent remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a Component and a service reference.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbComponentRef<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component and a service reference.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponentRef<S> add, CbComponentRef<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component and a service reference.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponentRef<S> add, CbComponentRef<S> change, CbComponentRef<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a Component and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbComponentService<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponentService<S> add, CbComponentService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponentService<S> add, CbComponentService<S> change, CbComponentService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added.
+ * The method reference must point to a method from an Object instance. Callback argument(s): a Component, a service reference, and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @return this builder
+ */
+ B cbi(CbComponentRefService<S> add);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component, a service reference, and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponentRefService<S> add, CbComponentRefService<S> remove);
+
+ /**
+ * Sets a <code>callback instance</code> invoked when a service is added/changed/removed.
+ * The method reference must point to method from an Object instance. Callback argument(s): a Component, a service reference, and a service.
+ *
+ * @param add the method reference invoked when a service is added.
+ * @param change the method reference invoked when a service is changed.
+ * @param remove the method reference invoked when a service is removed.
+ * @return this builder
+ */
+ B cbi(CbComponentRefService<S> add, CbComponentRefService<S> change, CbComponentRefService<S> remove);
+
+ /**
+ * Sets a swap <code>callback instance</code> invoked when a service is swapped.
+ * The method reference must point to a method from an Object instance. Callback argument(s): the old service, and the new service.
+ * the new service.
+ *
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ B swi(CbServiceService<S> swap);
+
+ /**
+ * Sets a swap <code>callback instance</code> invoked when a service is swapped.
+ * The method reference must point to a method from an Object instance. Callback argument(s): the component, the old service, and the new service.
+ * the new service.
+ *
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ B swi(CbComponentServiceService<S> swap);
+
+ /**
+ * Sets a swap <code>callback instance</code> invoked when a service is swapped.
+ * The method reference must point to a method from an Object instance. Callback argument(s): the old service reference, the old service, the
+ * new service reference, and the new service.
+ *
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ B swi(CbRefServiceRefService<S> swap);
+
+ /**
+ * Sets a swap <code>callback instance</code> invoked when a service is swapped.
+ * The method reference must point to a method from an Object instance. Callback argument(s): the component, old service reference, the old service, the
+ * new service reference, and the new service.
+ *
+ * @param swap the method reference invoked when the service is swapped.
+ * @return this builder
+ */
+ B swi(CbComponentRefServiceRefService<S> swap);
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceDependencyBuilder.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceDependencyBuilder.java
new file mode 100644
index 0000000..e2e4370
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/ServiceDependencyBuilder.java
@@ -0,0 +1,132 @@
+package org.apache.felix.dm.lambda;
+
+import java.util.Dictionary;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import org.apache.felix.dm.ServiceDependency;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Builds a Dependency Manager Service Dependency. Dependency callbacks can be defined using methods reflection like
+ * in original DM API, or using Java8 method references.
+ *
+ * Unlike with original DM, dependencies are required by default.
+ *
+ * @param <S> the type of the service dependency
+ */
+public interface ServiceDependencyBuilder<S> extends DependencyBuilder<ServiceDependency>, ServiceCallbacksBuilder<S, ServiceDependencyBuilder<S>> {
+ /**
+ * Configures the service dependency filter
+ * @param filter the service filter
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> filter(String filter);
+
+ /**
+ * Configures this dependency with the given ServiceReference.
+ * @param ref the service reference
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> ref(ServiceReference<S> ref);
+
+ /**
+ * Configures this dependency as optional. By default, a dependency is required.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> optional();
+
+ /**
+ * Configures this dependency as required. By default, a dependency is required.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> required();
+
+ /**
+ * Configures whether this dependency is required or not.
+ *
+ * @param required true if the dependency is required, false if not. Unlike with the original DM API, service dependencies are required by default.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> required(boolean required);
+
+ /**
+ * Configures debug mode
+ * @param label the label used by debug messages
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> debug(String label);
+
+ /**
+ * Propagates the dependency properties to the component service properties.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> propagate();
+
+ /**
+ * Configures whether the dependency properties must be propagated or not to the component service properties.
+ *
+ * @param propagate true if the service dependency properties should be propagated to the properties provided by the component using this dependency.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> propagate(boolean propagate);
+
+ /**
+ * Configures a method that can is called in order to get propagated service properties.
+ *
+ * @param instance an object instance
+ * @param method the method name to call on the object instance. This method returns the propagated service properties.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> propagate(Object instance, String method);
+
+ /**
+ * Specifies a function that is called to get the propagated service properties for this service dependency.
+ * @param propagate a function that is called to get the propagated service properties for this service dependency.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> propagate(Function<ServiceReference<S>, Dictionary<String, Object>> propagate);
+
+ /**
+ * Specifies a function that is called to get the propagated service properties for this service dependency.
+ * @param propagate a function that is called to get the propagated service properties for this service dependency.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> propagate(BiFunction<ServiceReference<S>, S, Dictionary<String, Object>> propagate);
+
+ /**
+ * Sets the default implementation if the service is not available.
+ * @param defaultImpl the implementation used by default when the service is not available.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> defImpl(Object defaultImpl);
+
+ /**
+ * Sets a timeout for this dependency. A timed dependency blocks the invoker thread is the required dependency is currently unavailable, until it comes up again.
+ * @param timeout the timeout to wait in milliseconds when the service disappears. If the timeout expires, an IllegalStateException is thrown
+ * when the missing service is invoked.
+ *
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> timeout(long timeout);
+
+ /**
+ * Injects this dependency in all fields matching the dependency type.
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> autoConfig();
+
+ /**
+ * Configures whether or not the dependency can be injected in all fields matching the dependency type.
+ * @param autoConfig true if the dependency can be injected in all fields matching the dependency type
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> autoConfig(boolean autoConfig);
+
+ /**
+ * Injects this dependency on the field with the given name
+ * @param field the field name where the dependency must be injected
+ * @return this builder
+ */
+ ServiceDependencyBuilder<S> autoConfig(String field);
+}
\ No newline at end of file
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbBundle.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbBundle.java
new file mode 100644
index 0000000..32d24b4
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbBundle.java
@@ -0,0 +1,27 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * Represents a callback(Bundle) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbBundle extends SerializableLambda {
+ /**
+ * Handles the given argument.
+ * @param bundle the callback parameter
+ */
+ void accept(Bundle bundle);
+
+ default CbBundle andThen(CbBundle after) {
+ Objects.requireNonNull(after);
+ return (Bundle bundle) -> {
+ accept(bundle);
+ after.accept(bundle);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponent.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponent.java
new file mode 100644
index 0000000..e5fbf41
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponent.java
@@ -0,0 +1,27 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponent {
+ /**
+ * Handles the given argument.
+ * @param component the callback parameter
+ */
+ void accept(Component component);
+
+ default CbComponent andThen(CbComponent after) {
+ Objects.requireNonNull(after);
+ return (Component component) -> {
+ accept(component);
+ after.accept(component);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentBundle.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentBundle.java
new file mode 100644
index 0000000..5049a25
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentBundle.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.Bundle;
+
+/**
+ * Represents a callback(Component, Bundle) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentBundle {
+ /**
+ * Handles the given arguments.
+ * @param component the callback parameter
+ * @param bundle the callback parameter
+ */
+ void accept(Component component, Bundle bundle);
+
+ default CbComponentBundle andThen(CbComponentBundle after) {
+ Objects.requireNonNull(after);
+ return (Component component, Bundle bundle) -> {
+ accept(component, bundle);
+ after.accept(component, bundle);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentDictionary.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentDictionary.java
new file mode 100644
index 0000000..1c0f525
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentDictionary.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, Dictionary) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentDictionary {
+ /**
+ * Handles the given arguments.
+ * @param component a Component
+ * @param properties some service properties
+ */
+ void accept(Component component, Dictionary<String, Object> properties);
+
+ default CbComponentDictionary andThen(CbComponentDictionary after) {
+ Objects.requireNonNull(after);
+ return (Component component, Dictionary<String, Object> properties) -> {
+ accept(component, properties);
+ after.accept(component, properties);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRef.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRef.java
new file mode 100644
index 0000000..956293d
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRef.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(Component, ServiceReference) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentRef<S> {
+ /**
+ * Handles the given arguments.
+ * @param c a Component
+ * @param ref the service reference
+ */
+ void accept(Component c, ServiceReference<S> ref);
+
+ default CbComponentRef<S> andThen(CbComponentRef<S> after) {
+ Objects.requireNonNull(after);
+ return (Component c, ServiceReference<S> ref) -> {
+ accept(c, ref);
+ after.accept(c, ref);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRefService.java
new file mode 100644
index 0000000..adf982d
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRefService.java
@@ -0,0 +1,30 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(Component, ServiceReference, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentRefService<S> {
+ /**
+ * Handles the given arguments.
+ * @param c a Component
+ * @param ref the service reference
+ * @param service the service
+ */
+ void accept(Component c, ServiceReference<S> ref, S service);
+
+ default CbComponentRefService<S> andThen(CbComponentRefService<S> after) {
+ Objects.requireNonNull(after);
+ return (Component c, ServiceReference<S> ref, S service) -> {
+ accept(c, ref, service);
+ after.accept(c, ref, service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRefServiceRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRefServiceRefService.java
new file mode 100644
index 0000000..6ea5e2a
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentRefServiceRefService.java
@@ -0,0 +1,32 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(Component, ServiceReference, Service, ServiceReference, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentRefServiceRefService<S> {
+ /**
+ * Handles the given arguments
+ * @param c a Component
+ * @param oldRef an old swapped service reference
+ * @param old an old swapped service
+ * @param replaceRef the new service reference
+ * @param replace the new service
+ */
+ void accept(Component c, ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace);
+
+ default CbComponentRefServiceRefService<S> andThen(CbComponentRefServiceRefService<S> after) {
+ Objects.requireNonNull(after);
+ return (Component c, ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace) -> {
+ accept(c, oldRef, old, replaceRef, replace);
+ after.accept(c, oldRef, old, replaceRef, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentService.java
new file mode 100644
index 0000000..7ddbe53
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentService.java
@@ -0,0 +1,28 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentService<S> {
+ /**
+ * Handles the given arguments
+ * @param c the component
+ * @param service the service
+ */
+ void accept(Component c, S service);
+
+ default CbComponentService<S> andThen(CbComponentService<S> after) {
+ Objects.requireNonNull(after);
+ return (Component c, S service) -> {
+ accept(c, service);
+ after.accept(c, service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentServiceService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentServiceService.java
new file mode 100644
index 0000000..cf8190a
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbComponentServiceService.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, Service, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbComponentServiceService<S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param c the component
+ * @param old the old service
+ * @param replace the new service
+ */
+ void accept(Component c, S old, S replace);
+
+ default CbComponentServiceService<S> andThen(CbComponentServiceService<S> after) {
+ Objects.requireNonNull(after);
+ return (Component c, S old, S replace) -> {
+ accept(c, old, replace);
+ after.accept(c, old, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbConsumer.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbConsumer.java
new file mode 100644
index 0000000..403ec7a
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbConsumer.java
@@ -0,0 +1,26 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback(T param) on an Object instance.
+ *
+ * @param T the type of the callback parameter.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbConsumer<T> extends SerializableLambda {
+ /**
+ * Handles the given argument
+ * @param t the argument
+ */
+ void accept(T t);
+
+ default CbConsumer<T> andThen(CbConsumer<? super T> after) {
+ Objects.requireNonNull(after);
+ return (T t) -> {
+ accept(t);
+ after.accept(t);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbDictionary.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbDictionary.java
new file mode 100644
index 0000000..dda1178
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbDictionary.java
@@ -0,0 +1,26 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+/**
+ * Represents a callback(Dictionary) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbDictionary {
+ /**
+ * Handles the given argument.
+ * @param conf the properties
+ */
+ void accept(Dictionary<String, Object> conf);
+
+ default CbDictionary andThen(CbDictionary after) {
+ Objects.requireNonNull(after);
+ return (Dictionary<String, Object> conf) -> {
+ accept(conf);
+ after.accept(conf);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbFuture.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbFuture.java
new file mode 100644
index 0000000..bab63af
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbFuture.java
@@ -0,0 +1,25 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback that accepts a the result of a CompletableFuture. The callback is invoked on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbFuture<F> {
+ /**
+ * Handles the result of a CompletableFuture operation.
+ * @param future the result of a CompletableFuture operation.
+ */
+ void accept(F future);
+
+ default CbFuture<F> andThen(CbFuture<? super F> after) {
+ Objects.requireNonNull(after);
+ return (F f) -> {
+ accept(f);
+ after.accept(f);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRef.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRef.java
new file mode 100644
index 0000000..6e5425c
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRef.java
@@ -0,0 +1,26 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(ServiceReference) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbRef<S> {
+ /**
+ * Handles the given argument
+ * @param ref a service reference
+ */
+ void accept(ServiceReference<S> ref);
+
+ default CbRef<S> andThen(CbRef<S> after) {
+ Objects.requireNonNull(after);
+ return (ServiceReference<S> ref) -> {
+ after.accept(ref);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRefService.java
new file mode 100644
index 0000000..ca795f4
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRefService.java
@@ -0,0 +1,28 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(ServiceReference, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbRefService<S> {
+ /**
+ * Handles the given arguments.
+ * @param ref a Service Reference
+ * @param service a Service
+ */
+ void accept(ServiceReference<S> ref, S service);
+
+ default CbRefService<S> andThen(CbRefService<S> after) {
+ Objects.requireNonNull(after);
+ return (ServiceReference<S> ref, S service) -> {
+ accept(ref, service);
+ after.accept(ref, service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRefServiceRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRefServiceRefService.java
new file mode 100644
index 0000000..7917ea3
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbRefServiceRefService.java
@@ -0,0 +1,30 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(ServiceReference, Service, ServiceReference, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbRefServiceRefService<S> {
+ /**
+ * Handles the given arguments
+ * @param oldRef a service reference
+ * @param old a service
+ * @param replaceRef a service reference
+ * @param replace a service
+ */
+ void accept(ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace);
+
+ default CbRefServiceRefService<S> andThen(CbRefServiceRefService<S> after) {
+ Objects.requireNonNull(after);
+ return (ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace) -> {
+ accept(oldRef, old, replaceRef, replace);
+ after.accept(oldRef, old, replaceRef, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbService.java
new file mode 100644
index 0000000..98ca2ab
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbService.java
@@ -0,0 +1,25 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback(Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbService<S> {
+ /**
+ * Handles the given argument.
+ * @param service a Service
+ */
+ void accept(S service);
+
+ default CbService<S> andThen(CbService<S> after) {
+ Objects.requireNonNull(after);
+ return (S service) -> {
+ accept(service);
+ after.accept(service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceDict.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceDict.java
new file mode 100644
index 0000000..0d88a18
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceDict.java
@@ -0,0 +1,27 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+/**
+ * Represents a callback(Service, Dictionary) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbServiceDict<S> {
+ /**
+ * Handles the given arguments.
+ * @param service a Service
+ * @param properties a Dictionary
+ */
+ void accept(S service, Dictionary<String, Object> properties);
+
+ default CbServiceDict<S> andThen(CbServiceDict<S> after) {
+ Objects.requireNonNull(after);
+ return (S service, Dictionary<String, Object> properties) -> {
+ accept(service, properties);
+ after.accept(service, properties);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceMap.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceMap.java
new file mode 100644
index 0000000..ae1d6c0
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceMap.java
@@ -0,0 +1,27 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Represents a callback(Service, Map) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbServiceMap<S> {
+ /**
+ * Handles the given arguments.
+ * @param service a Service
+ * @param properties a Map
+ */
+ void accept(S service, Map<String, Object> properties);
+
+ default CbServiceMap<S> andThen(CbServiceMap<S> after) {
+ Objects.requireNonNull(after);
+ return (S service, Map<String, Object> properties) -> {
+ accept(service, properties);
+ after.accept(service, properties);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceService.java
new file mode 100644
index 0000000..02c4d94
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbServiceService.java
@@ -0,0 +1,26 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback(Service, Service) on an Object instance.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbServiceService<S> extends SerializableLambda {
+ /**
+ * Handles the given argument
+ * @param old a Service
+ * @param replace a Service
+ */
+ void accept(S old, S replace);
+
+ default CbServiceService<S> andThen(CbServiceService<S> after) {
+ Objects.requireNonNull(after);
+ return (S old, S replace) -> {
+ accept(old, replace);
+ after.accept(old, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeBundle.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeBundle.java
new file mode 100644
index 0000000..aa6c444
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeBundle.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.Bundle;
+
+/**
+ * Represents a callback(Bundle) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeBundle<T> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param bundle the callback parameter
+ */
+ void accept(T instance, Bundle bundle);
+
+ default CbTypeBundle<T> andThen(CbTypeBundle<? super T> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Bundle bundle) -> {
+ accept(instance, bundle);
+ after.accept(instance, bundle);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponent.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponent.java
new file mode 100644
index 0000000..9bed1bd
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponent.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponent<T> extends SerializableLambda {
+ /**
+ * Handles the given arguments
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param component the callback parameter
+ */
+ void accept(T instance, Component component);
+
+ default CbTypeComponent<T> andThen(CbTypeComponent<T> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component component) -> {
+ accept(instance, component);
+ after.accept(instance, component);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentBundle.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentBundle.java
new file mode 100644
index 0000000..7bee3c3
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentBundle.java
@@ -0,0 +1,31 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.Bundle;
+
+/**
+ * Represents a callback(Component, Bundle) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentBundle<T> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param component the first callback parameter
+ * @param bundle the second callback parameter
+ */
+ void accept(T instance, Component component, Bundle bundle);
+
+ default CbTypeComponentBundle<T> andThen(CbTypeComponentBundle<? super T> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component component, Bundle bundle) -> {
+ accept(instance, component, bundle);
+ after.accept(instance, component, bundle);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentDictionary.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentDictionary.java
new file mode 100644
index 0000000..f84c71b
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentDictionary.java
@@ -0,0 +1,31 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, Dictionary) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentDictionary<T> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param component the first callback parameter
+ * @param conf the second callback parameter
+ */
+ void accept(T instance, Component component, Dictionary<String, Object> conf);
+
+ default CbTypeComponentDictionary<T> andThen(CbTypeComponentDictionary<? super T> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component component, Dictionary<String, Object> conf) -> {
+ accept(instance, component, conf);
+ after.accept(instance, component, conf);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRef.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRef.java
new file mode 100644
index 0000000..19bcb7d
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRef.java
@@ -0,0 +1,31 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(Component, ServiceReference) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentRef<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c the first callback parameter
+ * @param ref the second callback parameter
+ */
+ void accept(T instance, Component c, ServiceReference<S> ref);
+
+ default CbTypeComponentRef<T, S> andThen(CbTypeComponentRef<T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, ServiceReference<S> ref) -> {
+ accept(instance, c, ref);
+ after.accept(instance, c, ref);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRefService.java
new file mode 100644
index 0000000..c11e1a5
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRefService.java
@@ -0,0 +1,32 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(Component, ServiceReference, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentRefService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c the first callback parameter
+ * @param ref the second callback parameter
+ * @param service the third callback parameter
+ */
+ void accept(T instance, Component c, ServiceReference<S> ref, S service);
+
+ default CbTypeComponentRefService<T, S> andThen(CbTypeComponentRefService<T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, ServiceReference<S> ref, S service) -> {
+ accept(instance, c, ref, service);
+ after.accept(instance, c, ref, service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRefServiceRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRefServiceRefService.java
new file mode 100644
index 0000000..43ac90a
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentRefServiceRefService.java
@@ -0,0 +1,35 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(Component, ServiceReference, Service, ServiceReference, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentRefServiceRefService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c first callback param
+ * @param oldRef second callback param
+ * @param old third callback param
+ * @param replaceRef fourth callback param
+ * @param replace fifth callback param
+ */
+ void accept(T instance, Component c, ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace);
+
+ default CbTypeComponentRefServiceRefService<T, S> andThen(CbTypeComponentRefServiceRefService<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef,
+ S replace) -> {
+ accept(instance, c, oldRef, old, replaceRef, replace);
+ after.accept(instance, c, oldRef, old, replaceRef, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentService.java
new file mode 100644
index 0000000..705533d
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentService.java
@@ -0,0 +1,30 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c first callback param
+ * @param service second callback param
+ */
+ void accept(T instance, Component c, S service);
+
+ default CbTypeComponentService<T, S> andThen(CbTypeComponentService<T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, S s) -> {
+ accept(instance, c, s);
+ after.accept(instance, c, s);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceDict.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceDict.java
new file mode 100644
index 0000000..3fe4403
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceDict.java
@@ -0,0 +1,32 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, ServiceReference, Dictionary) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentServiceDict<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c first callback param
+ * @param service second callback param
+ * @param props third callback param
+ */
+ void accept(T instance, Component c, S service, Dictionary<String, Object> props);
+
+ default CbTypeComponentServiceDict<T, S> andThen(CbTypeComponentServiceDict<T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, S s, Dictionary<String, Object> props) -> {
+ accept(instance, c, s, props);
+ after.accept(instance, c, s, props);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceMap.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceMap.java
new file mode 100644
index 0000000..509cdc4
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceMap.java
@@ -0,0 +1,32 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, ServiceReference, Service, Service Reference, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentServiceMap<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c first callback param
+ * @param service second callback param
+ * @param props third callback param
+ */
+ void accept(T instance, Component c, S service, Map<String, Object> props);
+
+ default CbTypeComponentServiceMap<T, S> andThen(CbTypeComponentServiceMap<T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, S s, Map<String, Object> props) -> {
+ accept(instance, c, s, props);
+ after.accept(instance, c, s, props);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceService.java
new file mode 100644
index 0000000..d234a91
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeComponentServiceService.java
@@ -0,0 +1,31 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.apache.felix.dm.Component;
+
+/**
+ * Represents a callback(Component, Service, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeComponentServiceService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param c first callback param
+ * @param old second callback param
+ * @param replace third callback param
+ */
+ void accept(T instance, Component c, S old, S replace);
+
+ default CbTypeComponentServiceService<T, S> andThen(CbTypeComponentServiceService<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Component c, S old, S replace) -> {
+ accept(instance, c, old, replace);
+ after.accept(instance, c, old, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeDictionary.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeDictionary.java
new file mode 100644
index 0000000..8d4ceb1
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeDictionary.java
@@ -0,0 +1,28 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+/**
+ * Represents a callback(Dictionary) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeDictionary<T> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param conf first callback param
+ */
+ void accept(T instance, Dictionary<String, Object> conf);
+
+ default CbTypeDictionary<T> andThen(CbTypeDictionary<? super T> after) {
+ Objects.requireNonNull(after);
+ return (T instance, Dictionary<String, Object> conf) -> {
+ accept(instance, conf);
+ after.accept(instance, conf);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeFuture.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeFuture.java
new file mode 100644
index 0000000..54b0d72
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeFuture.java
@@ -0,0 +1,28 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback that accepts the result of a CompletableFuture operation. The callback is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ * The type of the result of the CompletableFuture is represented by the F generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeFuture<T, F> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param future the result of a CompletableFuture operation.
+ */
+ void accept(T instance, F future);
+
+ default CbTypeFuture<T, F> andThen(CbTypeFuture<? super T, F> after) {
+ Objects.requireNonNull(after);
+ return (T instance, F future) -> {
+ accept(instance, future);
+ after.accept(instance, future);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRef.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRef.java
new file mode 100644
index 0000000..36fa87c
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRef.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(ServiceReference) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeRef<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param service first callback param
+ */
+ void accept(T instance, ServiceReference<S> service);
+
+ default CbTypeRef<T, S> andThen(CbTypeRef<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, ServiceReference<S> ref) -> {
+ accept(instance, ref);
+ after.accept(instance, ref);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRefService.java
new file mode 100644
index 0000000..099416d
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRefService.java
@@ -0,0 +1,30 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(ServiceReference, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeRefService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param ref first callback param
+ * @param service second callback param
+ */
+ void accept(T instance, ServiceReference<S> ref, S service);
+
+ default CbTypeRefService<T, S> andThen(CbTypeRefService<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, ServiceReference<S> ref, S service) -> {
+ accept(instance, ref, service);
+ after.accept(instance, ref, service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRefServiceRefService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRefServiceRefService.java
new file mode 100644
index 0000000..ccb9142
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeRefServiceRefService.java
@@ -0,0 +1,32 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Represents a callback(ServiceReference, Service, ServiceReference, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeRefServiceRefService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param oldRef first callback param
+ * @param old second callback param
+ * @param replaceRef third callback param
+ * @param replace fourth callback param
+ */
+ void accept(T instance, ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace);
+
+ default CbTypeRefServiceRefService<T, S> andThen(CbTypeRefServiceRefService<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, ServiceReference<S> oldRef, S old, ServiceReference<S> replaceRef, S replace) -> {
+ accept(instance, oldRef, old, replaceRef, replace);
+ after.accept(instance, oldRef, old, replaceRef, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeService.java
new file mode 100644
index 0000000..01f518b
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeService.java
@@ -0,0 +1,27 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback(Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param service first callback param
+ */
+ void accept(T instance, S service);
+
+ default CbTypeFuture<T, S> andThen(CbTypeFuture<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, S service) -> {
+ accept(instance, service);
+ after.accept(instance, service);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceDict.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceDict.java
new file mode 100644
index 0000000..01c8abb
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceDict.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Dictionary;
+import java.util.Objects;
+
+/**
+ * Represents a callback(Component, Dictionary) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeServiceDict<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param service first callback param
+ * @param properties second callback param
+ */
+ void accept(T instance, S service, Dictionary<String, Object> properties);
+
+ default CbTypeServiceDict<T, S> andThen(CbTypeServiceDict<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, S service, Dictionary<String, Object> properties) -> {
+ accept(instance, service, properties);
+ after.accept(instance, service, properties);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceMap.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceMap.java
new file mode 100644
index 0000000..bfe875e
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceMap.java
@@ -0,0 +1,29 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Represents a callback(Component, Map) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeServiceMap<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param service first callback param
+ * @param properties second callback param
+ */
+ void accept(T instance, S service, Map<String, Object> properties);
+
+ default CbTypeServiceMap<T, S> andThen(CbTypeServiceMap<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, S service, Map<String, Object> properties) -> {
+ accept(instance, service, properties);
+ after.accept(instance, service, properties);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceService.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceService.java
new file mode 100644
index 0000000..a81aa72
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/CbTypeServiceService.java
@@ -0,0 +1,28 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.util.Objects;
+
+/**
+ * Represents a callback(Service, Service) that is invoked on a Component implementation class.
+ * The type of the class on which the callback is invoked on is represented by the T generic parameter.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+@FunctionalInterface
+public interface CbTypeServiceService<T, S> extends SerializableLambda {
+ /**
+ * Handles the given arguments.
+ * @param instance the Component implementation instance on which the callback is invoked on.
+ * @param old first callback param
+ * @param replace second callback param
+ */
+ void accept(T instance, S old, S replace);
+
+ default CbTypeServiceService<T, S> andThen(CbTypeServiceService<? super T, S> after) {
+ Objects.requireNonNull(after);
+ return (T instance, S old, S replace) -> {
+ accept(instance, old, replace);
+ after.accept(instance, old, replace);
+ };
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/SerializableLambda.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/SerializableLambda.java
new file mode 100644
index 0000000..b9427eb
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/SerializableLambda.java
@@ -0,0 +1,9 @@
+package org.apache.felix.dm.lambda.callbacks;
+
+import java.io.Serializable;
+
+/**
+ * Base interface for serializable lambdas. Some lambda must be serializable in order to allow to introspect their type and method signatures.
+ */
+public interface SerializableLambda extends Serializable {
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/packageinfo b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/packageinfo
new file mode 100644
index 0000000..9ad81f6
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/callbacks/packageinfo
@@ -0,0 +1 @@
+version 1.0.0
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/AdapterBase.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/AdapterBase.java
new file mode 100644
index 0000000..c884793
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/AdapterBase.java
@@ -0,0 +1,338 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.Dictionary;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.apache.felix.dm.lambda.BundleDependencyBuilder;
+import org.apache.felix.dm.lambda.ComponentBuilder;
+import org.apache.felix.dm.lambda.ConfigurationDependencyBuilder;
+import org.apache.felix.dm.lambda.FluentProperties;
+import org.apache.felix.dm.lambda.FutureDependencyBuilder;
+import org.apache.felix.dm.lambda.ServiceDependencyBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbComponent;
+import org.apache.felix.dm.lambda.callbacks.CbConsumer;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponent;
+
+/**
+ * Methods common to extended components like adapters or aspects.
+ *
+ * TODO javadoc
+ */
+@SuppressWarnings({"unchecked"})
+public interface AdapterBase<B extends ComponentBuilder<B>> extends ComponentBuilder<B> {
+
+ void andThenBuild(Consumer<ComponentBuilder<?>> builder);
+
+ default B impl(Object impl) {
+ andThenBuild(compBuilder -> compBuilder.impl(impl));
+ return (B) this;
+ }
+
+ default <U> B impl(Class<U> implClass) {
+ andThenBuild(compBuilder -> compBuilder.impl(implClass));
+ return (B) this;
+ }
+
+ default B factory(Object factory, String createMethod) {
+ andThenBuild(compBuilder -> compBuilder.factory(factory, createMethod));
+ return (B) this;
+ }
+
+ default B factory(Supplier<?> create) {
+ andThenBuild(compBuilder -> compBuilder.factory(create));
+ return (B) this;
+ }
+
+ default <U, V> B factory(Supplier<U> factory, Function<U, V> create) {
+ andThenBuild(compBuilder -> compBuilder.factory(factory, create));
+ return (B) this;
+ }
+
+ default B factory(Supplier<?> factory, Supplier<Object[]> getComposition) {
+ andThenBuild(compBuilder -> compBuilder.factory(factory, getComposition));
+ return (B) this;
+ }
+
+ default <U> B factory(Supplier<U> factory, Function<U, ?> create, Function<U, Object[]> getComposition) {
+ andThenBuild(compBuilder -> compBuilder.factory(factory, create, getComposition));
+ return (B) this;
+ }
+
+ default B provides(Class<?> iface) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface));
+ return (B) this;
+ }
+
+ default B provides(Class<?> iface, String name, Object value, Object ... rest) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface, name, value, rest));
+ return (B) this;
+ }
+
+ default B provides(Class<?> iface, FluentProperties ... properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface, properties));
+ return (B) this;
+ }
+
+ default B provides(Class<?> iface, Dictionary<?,?> properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface, properties));
+ return (B) this;
+ }
+
+ default B provides(Class<?>[] ifaces) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces));
+ return (B) this;
+ }
+
+ default B provides(Class<?>[] ifaces, String name, Object value, Object ... rest) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces, name, value, rest));
+ return (B) this;
+ }
+
+ default B provides(Class<?>[] ifaces, FluentProperties ... properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces, properties));
+ return (B) this;
+ }
+
+ default B provides(Class<?>[] ifaces, Dictionary<?,?> properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces, properties));
+ return (B) this;
+ }
+
+ default B provides(String iface) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface));
+ return (B) this;
+ }
+
+ default B provides(String iface, String name, Object value, Object ... rest) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface, name, value, rest));
+ return (B) this;
+ }
+
+ default B provides(String iface, FluentProperties ... properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface, properties));
+ return (B) this;
+ }
+
+ default B provides(String iface, Dictionary<?,?> properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(iface, properties));
+ return (B) this;
+ }
+
+ default B provides(String[] ifaces) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces));
+ return (B) this;
+ }
+
+ default B provides(String[] ifaces, String name, Object value, Object ... rest) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces, name, value, rest));
+ return (B) this;
+ }
+
+ default B provides(String[] ifaces, FluentProperties ... properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces, properties));
+ return (B) this;
+ }
+
+ default B provides(String[] ifaces, Dictionary<?,?> properties) {
+ andThenBuild(compBuilder -> compBuilder.provides(ifaces, properties));
+ return (B) this;
+ }
+
+ default B properties(Dictionary<?, ?> properties) {
+ andThenBuild(compBuilder -> compBuilder.properties(properties));
+ return (B) this;
+ }
+
+ default B properties(String name, Object value, Object ... rest) {
+ andThenBuild(compBuilder -> compBuilder.properties(name, value, rest));
+ return (B) this;
+ }
+
+ default B properties(FluentProperties ...properties) {
+ andThenBuild(compBuilder -> compBuilder.properties(properties));
+ return (B) this;
+ }
+
+ default B withSrv(Class<?> service, String filter) {
+ andThenBuild(compBuilder -> compBuilder.withSrv(service, filter));
+ return (B) this;
+ }
+
+ default B withSrv(Class<?> ... services) {
+ andThenBuild(compBuilder -> compBuilder.withSrv(services));
+ return (B) this;
+ }
+
+ default <U> B withSrv(Class<U> service, Consumer<ServiceDependencyBuilder<U>> consumer) {
+ andThenBuild(compBuilder -> compBuilder.withSrv(service, consumer));
+ return (B) this;
+ }
+
+ default B withCnf(Consumer<ConfigurationDependencyBuilder> consumer) {
+ andThenBuild(compBuilder -> compBuilder.withCnf(consumer));
+ return (B) this;
+ }
+
+ default B withBundle(Consumer<BundleDependencyBuilder> consumer) {
+ andThenBuild(compBuilder -> compBuilder.withBundle(consumer));
+ return (B) this;
+ }
+
+ default <U> B withFuture(CompletableFuture<U> future, Consumer<FutureDependencyBuilder<U>> consumer) {
+ andThenBuild(compBuilder -> compBuilder.withFuture(future, consumer));
+ return (B) this;
+ }
+
+ default B init(String callback) {
+ andThenBuild(compBuilder -> compBuilder.init(callback));
+ return (B) this;
+ }
+
+ default B start(String callback) {
+ andThenBuild(compBuilder -> compBuilder.start(callback));
+ return (B) this;
+ }
+
+ default B stop(String callback) {
+ andThenBuild(compBuilder -> compBuilder.stop(callback));
+ return (B) this;
+ }
+
+ default B destroy(String callback) {
+ andThenBuild(compBuilder -> compBuilder.destroy(callback));
+ return (B) this;
+ }
+
+ default B init(Object callbackInstance, String callback) {
+ andThenBuild(compBuilder -> compBuilder.init(callbackInstance, callback));
+ return (B) this;
+ }
+
+ default B start(Object callbackInstance, String callback) {
+ andThenBuild(compBuilder -> compBuilder.start(callbackInstance, callback));
+ return (B) this;
+ }
+
+ default B stop(Object callbackInstance, String callback) {
+ andThenBuild(compBuilder -> compBuilder.stop(callbackInstance, callback));
+ return (B) this;
+ }
+
+ default B destroy(Object callbackInstance, String callback) {
+ andThenBuild(compBuilder -> compBuilder.destroy(callbackInstance, callback));
+ return (B) this;
+ }
+
+ default <U> B init(CbConsumer<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.init(callback));
+ return (B) this;
+ }
+
+ default <U> B start(CbConsumer<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.start(callback));
+ return (B) this;
+ }
+
+ default <U> B stop(CbConsumer<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.stop(callback));
+ return (B) this;
+ }
+
+ default <U> B destroy(CbConsumer<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.destroy(callback));
+ return (B) this;
+ }
+
+ default <U> B init(CbTypeComponent<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.init(callback));
+ return (B) this;
+ }
+
+ default <U> B start(CbTypeComponent<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.start(callback));
+ return (B) this;
+ }
+
+ default <U> B stop(CbTypeComponent<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.stop(callback));
+ return (B) this;
+ }
+
+ default <U> B destroy(CbTypeComponent<U> callback) {
+ andThenBuild(compBuilder -> compBuilder.destroy(callback));
+ return (B) this;
+ }
+
+ default B initInstance(Runnable callback) {
+ andThenBuild(compBuilder -> compBuilder.initInstance(callback));
+ return (B) this;
+ }
+
+ default B startInstance(Runnable callback) {
+ andThenBuild(compBuilder -> compBuilder.startInstance(callback));
+ return (B) this;
+ }
+
+ default B stopInstance(Runnable callback) {
+ andThenBuild(compBuilder -> compBuilder.stopInstance(callback));
+ return (B) this;
+ }
+
+ default B destroyInstance(Runnable callback) {
+ andThenBuild(compBuilder -> compBuilder.destroyInstance(callback));
+ return (B) this;
+ }
+
+ default B initInstance(CbComponent callback) {
+ andThenBuild(compBuilder -> compBuilder.initInstance(callback));
+ return (B) this;
+ }
+
+ default B startInstance(CbComponent callback) {
+ andThenBuild(compBuilder -> compBuilder.startInstance(callback));
+ return (B) this;
+ }
+
+ default B stopInstance(CbComponent callback) {
+ andThenBuild(compBuilder -> compBuilder.stopInstance(callback));
+ return (B) this;
+ }
+
+ default B destroyInstance(CbComponent callback) {
+ andThenBuild(compBuilder -> compBuilder.destroyInstance(callback));
+ return (B) this;
+ }
+
+ default B autoConfig(Class<?> clazz, boolean autoConfig) {
+ andThenBuild(compBuilder -> compBuilder.autoConfig(clazz, autoConfig));
+ return (B) this;
+ }
+
+ default B autoConfig(Class<?> clazz, String field) {
+ andThenBuild(compBuilder -> compBuilder.autoConfig(clazz, field));
+ return (B) this;
+ }
+
+ default B debug(String label) {
+ andThenBuild(compBuilder -> compBuilder.debug(label));
+ return (B) this;
+ }
+
+ default B composition(String getCompositionMethod) {
+ andThenBuild(compBuilder -> compBuilder.composition(getCompositionMethod));
+ return (B) this;
+ }
+
+ default B composition(Object instance, String getCompositionMethod) {
+ andThenBuild(compBuilder -> compBuilder.composition(instance, getCompositionMethod));
+ return (B) this;
+ }
+
+ default B composition(Supplier<Object[]> getCompositionMethod) {
+ andThenBuild(compBuilder -> compBuilder.composition(getCompositionMethod));
+ return (B) this;
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/BundleAdapterBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/BundleAdapterBuilderImpl.java
new file mode 100644
index 0000000..8cd257e
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/BundleAdapterBuilderImpl.java
@@ -0,0 +1,260 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.BundleAdapterBuilder;
+import org.apache.felix.dm.lambda.ComponentBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbBundle;
+import org.apache.felix.dm.lambda.callbacks.CbComponentBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentBundle;
+import org.osgi.framework.Bundle;
+
+public class BundleAdapterBuilderImpl implements AdapterBase<BundleAdapterBuilder>, BundleAdapterBuilder {
+ private Consumer<ComponentBuilder<?>> m_compBuilder = (compBuilder -> {});
+ protected final Map<Cb, List<MethodRef<Object>>> m_refs = new HashMap<>();
+ private DependencyManager m_dm;
+ private boolean m_autoAdd;
+ private String m_added;
+ private String m_changed;
+ private String m_removed;
+ private String m_filter;
+ private int m_stateMask = -1;
+ private boolean m_propagate;
+ private Object m_callbackInstance;
+ private String m_add;
+ private String m_change;
+ private String m_remove;
+
+ enum Cb {
+ ADD,
+ CHG,
+ REM
+ };
+
+ @FunctionalInterface
+ interface MethodRef<I> {
+ public void accept(I instance, Component c, Bundle b);
+ }
+
+ public BundleAdapterBuilderImpl(DependencyManager dm) {
+ m_dm = dm;
+ }
+
+ public void andThenBuild(Consumer<ComponentBuilder<?>> builder) {
+ m_compBuilder = m_compBuilder.andThen(builder);
+ }
+
+ @Override
+ public BundleAdapterBuilderImpl autoAdd(boolean autoAdd) {
+ m_autoAdd = autoAdd;
+ return this;
+ }
+
+ public boolean isAutoAdd() {
+ return m_autoAdd;
+ }
+
+ public BundleAdapterBuilder mask(int mask) {
+ m_stateMask = mask;
+ return this;
+ }
+
+ public BundleAdapterBuilder filter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+ public BundleAdapterBuilder propagate(boolean propagate) {
+ m_propagate = propagate;
+ return this;
+ }
+
+ public BundleAdapterBuilder propagate() {
+ m_propagate = true;
+ return this;
+ }
+
+ public BundleAdapterBuilder cb(String ... callbacks) {
+ return cbi(null, callbacks);
+ }
+
+ public BundleAdapterBuilder cbi(Object callbackInstance, String ... callbacks) {
+ switch (callbacks.length) {
+ case 1:
+ return cbi(callbackInstance, callbacks[0], null, null);
+
+ case 2:
+ return cbi(callbackInstance, callbacks[0], null, callbacks[1]);
+
+ case 3:
+ return cbi(callbackInstance, callbacks[0], callbacks[1], callbacks[2]);
+
+ default:
+ throw new IllegalArgumentException("wrong number of arguments: " + callbacks.length + ". " +
+ "Possible arguments: [add], [add, remove] or [add, change, remove]");
+ }
+ }
+
+ private BundleAdapterBuilder cbi(Object callbackInstance, String add, String change, String remove) {
+ checkHasNoMethodRefs();
+ m_callbackInstance = callbackInstance;
+ m_add = add;
+ m_change = change;
+ m_remove = remove;
+ return this;
+ }
+
+ public <T> BundleAdapterBuilder cb(CbTypeBundle<T> add) {
+ return cb(add, (CbTypeBundle<T>) null, (CbTypeBundle<T>) null);
+ }
+
+ public <T> BundleAdapterBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> BundleAdapterBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> change, CbTypeBundle<T> remove) {
+ if (add != null) {
+ Class<T> type = Helpers.getLambdaArgType(add, 0);
+ setComponentCallbackRef(Cb.ADD, type, (instance, component, bundle) -> { add.accept((T) instance, bundle); });
+ }
+ if (change != null) {
+ Class<T> type = Helpers.getLambdaArgType(change, 0);
+ setComponentCallbackRef(Cb.CHG, type, (instance, component, bundle) -> { change.accept((T) instance, bundle); });
+ }
+ if (remove != null) {
+ Class<T> type = Helpers.getLambdaArgType(remove, 0);
+ setComponentCallbackRef(Cb.REM, type, (instance, component, bundle) -> { remove.accept((T) instance, bundle); });
+ }
+ return this;
+ }
+
+ public BundleAdapterBuilder cbi(CbBundle add) {
+ return cbi(add, null, null);
+ }
+
+ public BundleAdapterBuilder cbi(CbBundle add, CbBundle remove) {
+ return cbi(add, null, remove);
+ }
+
+ public BundleAdapterBuilder cbi(CbBundle add, CbBundle change, CbBundle remove) {
+ if (add != null) setInstanceCallbackRef(Cb.ADD, (instance, component, bundle) -> { add.accept(bundle); });
+ if (change != null) setInstanceCallbackRef(Cb.CHG, (instance, component, bundle) -> { change.accept(bundle); });
+ if (remove != null) setInstanceCallbackRef(Cb.REM, (instance, component, bundle) -> { remove.accept(bundle); });
+ return this;
+ }
+
+ public <T> BundleAdapterBuilder cb(CbTypeComponentBundle<T> add) {
+ return cb((CbTypeComponentBundle<T>) add, (CbTypeComponentBundle<T>) null, (CbTypeComponentBundle<T>) null);
+ }
+
+ public <T> BundleAdapterBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> BundleAdapterBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> change, CbTypeComponentBundle<T> remove) {
+ if (add != null) {
+ Class<T> type = Helpers.getLambdaArgType(add, 0);
+ return setComponentCallbackRef(Cb.ADD, type, (instance, component, bundle) -> { add.accept((T) instance, component, bundle); });
+ }
+ if (change != null) {
+ Class<T> type = Helpers.getLambdaArgType(change, 0);
+ return setComponentCallbackRef(Cb.CHG, type, (instance, component, bundle) -> { change.accept((T) instance, component, bundle); });
+ }
+ if (remove != null) {
+ Class<T> type = Helpers.getLambdaArgType(remove, 0);
+ return setComponentCallbackRef(Cb.ADD, type, (instance, component, bundle) -> { remove.accept((T) instance, component, bundle); });
+ }
+ return this;
+ }
+
+ public BundleAdapterBuilder cbi(CbComponentBundle add) {
+ return cbi(add, null, null);
+ }
+
+ public BundleAdapterBuilder cbi(CbComponentBundle add, CbComponentBundle remove) {
+ return cbi(add, null, remove);
+ }
+
+ public BundleAdapterBuilder cbi(CbComponentBundle add, CbComponentBundle change, CbComponentBundle remove) {
+ if (add != null) setInstanceCallbackRef(Cb.ADD, (instance, component, bundle) -> { add.accept(component, bundle); });
+ if (change != null) setInstanceCallbackRef(Cb.CHG, (instance, component, bundle) -> { change.accept(component, bundle); });
+ if (remove != null) setInstanceCallbackRef(Cb.REM, (instance, component, bundle) -> { remove.accept(component, bundle); });
+ return this;
+ }
+
+ @Override
+ public Component build() {
+ Component c = null;
+
+ if (m_refs.size() > 0) {
+ @SuppressWarnings("unused")
+ Object wrapCallback = new Object() {
+ public void add(Component comp, Bundle bundle) {
+ invokeMethodRefs(Cb.ADD, comp, bundle);
+ }
+
+ public void change(Component comp, Bundle bundle) {
+ invokeMethodRefs(Cb.CHG, comp, bundle);
+ }
+
+ public void remove(Component comp, Bundle bundle) {
+ invokeMethodRefs(Cb.REM, comp, bundle);
+ }
+ };
+ c = m_dm.createBundleAdapterService(m_stateMask, m_filter, m_propagate, wrapCallback, "add", "change", "remove");
+ } else {
+ c = m_dm.createBundleAdapterService(m_stateMask, m_filter, m_propagate, m_callbackInstance, m_add, m_change, m_remove);
+ }
+ ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false);
+ m_compBuilder.accept (cb);
+ return cb.build();
+ }
+
+ private <U> BundleAdapterBuilder setInstanceCallbackRef(Cb cbType, MethodRef<U> ref) {
+ checkHasNoReflectionCallbacks();
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component, bundle) -> ref.accept(null, component, bundle));
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <U> BundleAdapterBuilder setComponentCallbackRef(Cb cbType, Class<U> type, MethodRef<U> ref) {
+ checkHasNoReflectionCallbacks();
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component, bundle) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
+ ref.accept((U) componentImpl, component, bundle);
+ });
+ return this;
+ }
+
+ private void invokeMethodRefs(Cb cbType, Component comp, Bundle bundle) {
+ m_refs.computeIfPresent(cbType, (k, mrefs) -> {
+ mrefs.forEach(mref -> mref.accept(null, comp, bundle));
+ return mrefs;
+ });
+ }
+
+ private void checkHasNoMethodRefs() {
+ if (m_refs.size() > 0) {
+ throw new IllegalStateException("Can't mix method references with reflection based callbacks");
+ }
+ }
+
+ private void checkHasNoReflectionCallbacks() {
+ if (m_added != null || m_changed != null || m_removed != null) {
+ throw new IllegalStateException("Can't mix method references with reflection based callbacks");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/BundleDependencyBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/BundleDependencyBuilderImpl.java
new file mode 100644
index 0000000..fe77432
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/BundleDependencyBuilderImpl.java
@@ -0,0 +1,359 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.BundleDependency;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.BundleDependencyBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbBundle;
+import org.apache.felix.dm.lambda.callbacks.CbComponentBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeBundle;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentBundle;
+import org.osgi.framework.Bundle;
+
+@SuppressWarnings("unchecked")
+public class BundleDependencyBuilderImpl implements BundleDependencyBuilder {
+ private String m_added;
+ private String m_changed;
+ private String m_removed;
+ private Object m_instance;
+ private boolean m_autoConfig = true;
+ private boolean m_autoConfigInvoked = false;
+ private boolean m_required = true;
+ private Bundle m_bundle;
+ private String m_filter;
+ private int m_stateMask = -1;
+ private boolean m_propagate;
+ private Object m_propagateInstance;
+ private String m_propagateMethod;
+ private Supplier<Dictionary<?, ?>> m_propagateSupplier;
+ private final Component m_component;
+
+ enum Cb {
+ ADD,
+ CHG,
+ REM
+ };
+
+ private final Map<Cb, List<MethodRef<Object>>> m_refs = new HashMap<>();
+
+ @FunctionalInterface
+ interface MethodRef<I> {
+ public void accept(I instance, Component c, Bundle bundle);
+ }
+
+ /**
+ * Class used to call a supplier that returns Propagated properties
+ */
+ private class Propagate {
+ @SuppressWarnings("unused")
+ Dictionary<?, ?> propagate() {
+ return m_propagateSupplier.get();
+ }
+ }
+
+ public BundleDependencyBuilderImpl (Component component) {
+ m_component = component;
+ }
+
+ @Override
+ public BundleDependencyBuilder autoConfig(boolean autoConfig) {
+ m_autoConfig = autoConfig;
+ m_autoConfigInvoked = true;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder autoConfig() {
+ autoConfig(true);
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder required(boolean required) {
+ m_required = required;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder required() {
+ required(true);
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder bundle(Bundle bundle) {
+ m_bundle = bundle;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder filter(String filter) throws IllegalArgumentException {
+ m_filter = filter;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder mask(int mask) {
+ m_stateMask = mask;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder propagate(boolean propagate) {
+ m_propagate = propagate;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder propagate() {
+ propagate(true);
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder propagate(Object instance, String method) {
+ if (m_propagateSupplier != null || m_propagate) throw new IllegalStateException("Propagate callback already set.");
+ Objects.nonNull(method);
+ Objects.nonNull(instance);
+ m_propagateInstance = instance;
+ m_propagateMethod = method;
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder propagate(Supplier<Dictionary<?, ?>> instance) {
+ if (m_propagateInstance != null || m_propagate) throw new IllegalStateException("Propagate callback already set.");
+ m_propagateSupplier = instance;
+ return this;
+ }
+
+ public BundleDependencyBuilder cb(String ... callbacks) {
+ return cb(null, callbacks);
+ }
+
+ @Override
+ public BundleDependencyBuilder cb(Object callbackInstance, String ... callbacks) {
+ switch (callbacks.length) {
+ case 1:
+ cbi(callbackInstance, callbacks[0], null, null);
+ break;
+
+ case 2:
+ cbi(callbackInstance, callbacks[0], null, callbacks[1]);
+ break;
+
+ case 3:
+ cbi(callbackInstance, callbacks[0], callbacks[1], callbacks[2]);
+ break;
+
+ default:
+ throw new IllegalArgumentException("wrong number of arguments: " + callbacks.length + ". " +
+ "Possible arguments: [add], [add, remove] or [add, change, remove]");
+ }
+
+ return this;
+ }
+
+ private BundleDependencyBuilder cbi(Object callbackInstance, String added, String changed, String removed) {
+ requiresNoMethodRefs();
+ m_instance = callbackInstance;
+ m_added = added != null ? added : m_added;
+ m_changed = changed != null ? changed : m_changed;
+ m_removed = removed != null ? removed : m_removed;
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ return this;
+ }
+
+ @Override
+ public <T> BundleDependencyBuilder cb(CbTypeBundle<T> add) {
+ return cb(add, null, null);
+ }
+
+ @Override
+ public <T> BundleDependencyBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> remove) {
+ return cb(add, null, remove);
+ }
+
+ @Override
+ public <T> BundleDependencyBuilder cb(CbTypeBundle<T> add, CbTypeBundle<T> change, CbTypeBundle<T> remove) {
+ if (add != null) {
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, component, bundle) -> add.accept ((T) inst, bundle));
+ }
+ if (change != null) {
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, component, bundle) -> change.accept ((T) inst, bundle));
+ }
+ if (remove != null) {
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, component, bundle) -> remove.accept ((T) inst, bundle));
+ }
+ return this;
+ }
+
+ @Override
+ public <T> BundleDependencyBuilder cb(CbTypeComponentBundle<T> add) {
+ return cb(add, null, null);
+ }
+
+ @Override
+ public <T> BundleDependencyBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> remove) {
+ return cb(add, null, remove);
+ }
+
+ @Override
+ public <T> BundleDependencyBuilder cb(CbTypeComponentBundle<T> add, CbTypeComponentBundle<T> change, CbTypeComponentBundle<T> remove) {
+ if (add != null) {
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, component, bundle) -> add.accept ((T) inst, component, bundle));
+ }
+ if (change != null) {
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, component, bundle) -> change.accept ((T) inst, component, bundle));
+ }
+ if (remove != null) {
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, component, bundle) -> remove.accept ((T) inst, component, bundle));
+ }
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder cbi(CbBundle add) {
+ return cbi(add, null, null);
+ }
+
+ @Override
+ public BundleDependencyBuilder cbi(CbBundle add, CbBundle remove) {
+ return cbi(add, null, remove);
+ }
+
+ @Override
+ public BundleDependencyBuilder cbi(CbBundle add, CbBundle change, CbBundle remove) {
+ if (add != null) setInstanceCallbackRef(Cb.ADD, (inst, component, bundle) -> add.accept(bundle));
+ if (change != null) setInstanceCallbackRef(Cb.CHG, (inst, component, bundle) -> change.accept(bundle));
+ if (remove != null) setInstanceCallbackRef(Cb.REM, (inst, component, bundle) -> remove.accept(bundle));
+ return this;
+ }
+
+ @Override
+ public BundleDependencyBuilder cbi(CbComponentBundle add) {
+ return cbi(add, null, null);
+ }
+
+ @Override
+ public BundleDependencyBuilder cbi(CbComponentBundle add, CbComponentBundle remove) {
+ return cbi(add, null, remove);
+ }
+
+ @Override
+ public BundleDependencyBuilder cbi(CbComponentBundle add, CbComponentBundle change, CbComponentBundle remove) {
+ if (add != null) setInstanceCallbackRef(Cb.ADD, (inst, component, bundle) -> add.accept(component, bundle));
+ if (change != null) setInstanceCallbackRef(Cb.CHG, (inst, component, bundle) -> change.accept(component, bundle));
+ if (remove != null) setInstanceCallbackRef(Cb.REM, (inst, component, bundle) -> remove.accept(component, bundle));
+ return this;
+ }
+
+ @Override
+ public BundleDependency build() {
+ DependencyManager dm = m_component.getDependencyManager();
+
+ BundleDependency dep = dm.createBundleDependency();
+ dep.setRequired(m_required);
+
+ if (m_filter != null) {
+ dep.setFilter(m_filter);
+ }
+
+ if (m_bundle != null) {
+ dep.setBundle(m_bundle);
+ }
+
+ if (m_stateMask != -1) {
+ dep.setStateMask(m_stateMask);
+ }
+
+ if (m_propagate) {
+ dep.setPropagate(true);
+ } else if (m_propagateInstance != null) {
+ dep.setPropagate(m_propagateInstance, m_propagateMethod);
+ } else if (m_propagateSupplier != null) {
+ dep.setPropagate(new Propagate(), "propagate");
+ }
+
+ if (m_added != null || m_changed != null || m_removed != null) {
+ dep.setCallbacks(m_instance, m_added, m_changed, m_removed);
+ } else if (m_refs.size() > 0) {
+ Object cb = createCallbackInstance();
+ dep.setCallbacks(cb, "add", "change", "remove");
+ }
+
+ dep.setAutoConfig(m_autoConfig);
+ return dep;
+ }
+
+ private <T> BundleDependencyBuilder setInstanceCallbackRef(Cb cbType, MethodRef<T> ref) {
+ requiresNoStringCallbacks();
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component, bundle) -> ref.accept(null, component, bundle));
+ return this;
+ }
+
+ private <T> BundleDependencyBuilder setComponentCallbackRef(Cb cbType, Class<T> type, MethodRef<T> ref) {
+ requiresNoStringCallbacks();
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component, bundle) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
+ ref.accept((T) componentImpl, component, bundle);
+ });
+ return this;
+ }
+
+ @SuppressWarnings("unused")
+ private Object createCallbackInstance() {
+ Object cb = null;
+
+ cb = new Object() {
+ void add(Component c, Bundle bundle) {
+ invokeMethodRefs(Cb.ADD, c, bundle);
+ }
+
+ void change(Component c, Bundle bundle) {
+ invokeMethodRefs(Cb.CHG, c, bundle);
+ }
+
+ void remove(Component c, Bundle bundle) {
+ invokeMethodRefs(Cb.REM, c, bundle);
+ }
+ };
+
+ return cb;
+ }
+
+ private void invokeMethodRefs(Cb cbType, Component c, Bundle bundle) {
+ m_refs.computeIfPresent(cbType, (k, mrefs) -> {
+ mrefs.forEach(mref -> mref.accept(null, c, bundle));
+ return mrefs;
+ });
+ }
+
+ private void requiresNoStringCallbacks() {
+ if (m_added != null || m_changed != null || m_removed != null) {
+ throw new IllegalStateException("can't mix method references and string callbacks.");
+ }
+ }
+
+ private void requiresNoMethodRefs() {
+ if (m_refs.size() > 0) {
+ throw new IllegalStateException("can't mix method references and string callbacks.");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java
new file mode 100644
index 0000000..d41456f
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java
@@ -0,0 +1,241 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.context.AbstractDependency;
+import org.apache.felix.dm.context.DependencyContext;
+import org.apache.felix.dm.context.Event;
+import org.apache.felix.dm.context.EventType;
+import org.apache.felix.dm.lambda.FutureDependencyBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbFuture;
+import org.apache.felix.dm.lambda.callbacks.CbTypeFuture;
+import org.osgi.service.log.LogService;
+
+public class CompletableFutureDependencyImpl<F> extends AbstractDependency<CompletableFutureDependencyImpl<F>> implements FutureDependencyBuilder<F> {
+
+ private final CompletableFuture<F> m_future;
+ private Component m_comp;
+ private boolean m_async;
+ private Executor m_exec;
+ private CbFuture<F> m_accept = (future) -> {};
+ private CbTypeFuture<Object, F> m_accept2;
+ private Class<?> m_accept2Type;
+
+ public CompletableFutureDependencyImpl(Component c, CompletableFuture<F> future) {
+ super.setRequired(true);
+ m_future = future;
+ m_comp = c;
+ }
+
+ /**
+ * Create a new PathDependency from an existing prototype.
+ *
+ * @param prototype
+ * the existing PathDependency.
+ */
+ public CompletableFutureDependencyImpl(Component component, CompletableFutureDependencyImpl<F> prototype) {
+ super(prototype);
+ m_future = prototype.m_future;
+ m_comp = component;
+ }
+
+ @Override
+ public Dependency build() {
+ return this;
+ }
+
+ @Override
+ public FutureDependencyBuilder<F> cb(String callback) {
+ return cbi(null, callback);
+ }
+
+ @Override
+ public FutureDependencyBuilder<F> cbi(Object callbackInstance, String callback) {
+ super.setCallbacks(callbackInstance, callback, null);
+ return this;
+ }
+
+ @Override
+ public <T> FutureDependencyBuilder<F> cb(CbTypeFuture<T, ? super F> consumer) {
+ return cb(consumer, false);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> FutureDependencyBuilder<F> cb(CbTypeFuture<T, ? super F> consumer, boolean async) {
+ m_accept2Type = Helpers.getLambdaArgType(consumer, 0);;
+ m_accept2 = (instance, result) -> consumer.accept((T) instance, result);
+ m_async = async;
+ return this;
+ }
+
+ @Override
+ public <T> FutureDependencyBuilder<F> cb(CbTypeFuture<T, ? super F> consumer, Executor executor) {
+ cb(consumer, true /* async */);
+ m_exec = executor;
+ return this;
+ }
+
+ @Override
+ public FutureDependencyBuilder<F> cbi(CbFuture<? super F> consumer) {
+ cbi(consumer, false);
+ return this;
+ }
+
+ @Override
+ public FutureDependencyBuilder<F> cbi(CbFuture<? super F> consumer, boolean async) {
+ m_accept = m_accept.andThen(future -> consumer.accept(future));
+ m_async = async;
+ return this;
+ }
+
+ @Override
+ public FutureDependencyBuilder<F> cbi(CbFuture<? super F> consumer, Executor executor) {
+ cbi(consumer, true /* async */);
+ m_exec = executor;
+ return this;
+ }
+
+ // ---------- DependencyContext interface ----------
+
+ @Override
+ public void start() {
+ try {
+ if (m_async) {
+ if (m_exec != null) {
+ m_future.whenCompleteAsync((result, error) -> completed(result, error), m_exec);
+ } else {
+ m_future.whenCompleteAsync((result, error) -> completed(result, error));
+ }
+ } else {
+ m_future.whenComplete((result, error) -> completed(result, error));
+ }
+ } catch (Throwable error) {
+ super.getComponentContext().getLogger().log(LogService.LOG_ERROR, "completable future failed", error);
+ }
+ super.start();
+ }
+
+ @Override
+ public DependencyContext createCopy() {
+ return new CompletableFutureDependencyImpl<F>(m_comp, this);
+ }
+
+ @Override
+ public Class<?> getAutoConfigType() {
+ return null; // we don't support auto config mode
+ }
+
+ // ---------- ComponentDependencyDeclaration interface -----------
+
+ /**
+ * Returns the name of this dependency (a generic name with optional info
+ * separated by spaces). The DM Shell will use this method when displaying
+ * the dependency
+ **/
+ @Override
+ public String getSimpleName() {
+ return m_future.toString();
+ }
+
+ /**
+ * Returns the name of the type of this dependency. Used by the DM shell
+ * when displaying the dependency.
+ **/
+ @Override
+ public String getType() {
+ return "future";
+ }
+
+ /**
+ * Called by DM component implementation when all required dependencies are satisfied.
+ */
+ @Override
+ public void invokeCallback(EventType type, Event ... events) {
+ try {
+ switch (type) {
+ case ADDED:
+ if (m_add != null) {
+ // Inject result by reflection on a method name
+ injectByReflection(events[0].getEvent());
+ return;
+ }
+ F result = events[0].getEvent();
+ if (m_accept2 != null) {
+ if (m_accept2Type != null) {
+ // find the component instance that matches the given type
+ Object componentInstance = Stream.of(getComponentContext().getInstances())
+ .filter(instance -> Helpers.getClass(instance).equals(m_accept2Type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(
+ "accept callback is not on one of the component instances: " + m_accept2 + " (type=" + m_accept2Type + ")"));
+
+ m_accept2.accept(componentInstance, result);
+ } else {
+ // invoke a method in the main component instance that will handle the completed future.
+ m_accept2.accept(getComponentContext().getInstance(), result);
+ }
+ } else {
+ // Just invoke the Consumer with the completed future
+ m_accept.accept(result);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } catch (Throwable exc) {
+ super.getComponentContext().getLogger().log(LogService.LOG_ERROR, "completable future failed", exc);
+ }
+ }
+
+ // ---------- Private methods -----------
+
+ /**
+ * Triggers component activation when the future has completed.
+ * @param result
+ * @param error
+ */
+ private void completed(F result, Throwable error) {
+ if (error != null) {
+ super.getComponentContext().getLogger().log(LogService.LOG_ERROR, "completable future failed", error);
+ } else {
+ // Will trigger component activation (if other dependencies are satisfied), and our invokeCallback method will then be called.
+ m_component.handleEvent(this, EventType.ADDED, new Event(result));
+ }
+ }
+
+ /**
+ * Injects the completed fiture result in a method by reflection.
+ * We try to find a method which has in its signature a parameter that is compatible with the future result
+ * (including any interfaces the result may implements).
+ *
+ * @param result the result of the completable future.
+ */
+ private void injectByReflection(Object result) {
+ List<Class<?>> types = new ArrayList<>();
+ Class<?> currentClazz = result.getClass();
+
+ while (currentClazz != null && currentClazz != Object.class) {
+ types.add(currentClazz);
+ Stream.of(currentClazz.getInterfaces()).forEach(types::add);
+ currentClazz = currentClazz.getSuperclass();
+ }
+
+ Class<?>[][] classes = new Class<?>[types.size() + 1][1];
+ Object[][] results = new Object[types.size() + 1][1];
+ for (int i = 0; i < types.size(); i ++) {
+ classes[i] = new Class<?>[] { types.get(i) };
+ results[i] = new Object[] { result };
+ }
+ classes[types.size()] = new Class<?>[0];
+ results[types.size()] = new Object[0];
+ m_component.invokeCallbackMethod(getInstances(), m_add, classes, results);
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java
new file mode 100644
index 0000000..73f2687
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java
@@ -0,0 +1,728 @@
+package org.apache.felix.dm.lambda.impl;
+
+import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.DESTROY;
+import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.INIT;
+import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.START;
+import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.STOP;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.BundleDependencyBuilder;
+import org.apache.felix.dm.lambda.ComponentBuilder;
+import org.apache.felix.dm.lambda.ConfigurationDependencyBuilder;
+import org.apache.felix.dm.lambda.DependencyBuilder;
+import org.apache.felix.dm.lambda.FluentProperties;
+import org.apache.felix.dm.lambda.FutureDependencyBuilder;
+import org.apache.felix.dm.lambda.ServiceDependencyBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbComponent;
+import org.apache.felix.dm.lambda.callbacks.CbConsumer;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponent;
+
+public class ComponentBuilderImpl implements ComponentBuilder<ComponentBuilderImpl> {
+ private final List<DependencyBuilder<?>> m_dependencyBuilders = new ArrayList<>();
+ private final Component m_component;
+ private final boolean m_componentUpdated;
+ private String[] m_serviceNames;
+ private Dictionary<Object, Object> m_properties;
+ private Object m_impl;
+ private Object m_factory;
+ private boolean m_factoryHasComposite;
+ private boolean m_autoAdd = true;
+ protected final Map<ComponentCallback, List<MethodRef<Object>>> m_refs = new HashMap<>();
+ private Object m_compositionInstance;
+ private String m_compositionMethod;
+ private String m_init;
+ private String m_stop;
+ private String m_start;
+ private String m_destroy;
+ private Object m_callbackInstance;
+ private String m_factoryCreateMethod;
+ private boolean m_hasFactoryRef;
+ private boolean m_hasFactory;
+
+ enum ComponentCallback { INIT, START, STOP, DESTROY };
+
+ @FunctionalInterface
+ interface MethodRef<I> {
+ public void accept(I instance, Component c);
+ }
+
+ public ComponentBuilderImpl(DependencyManager dm) {
+ m_component = dm.createComponent();
+ m_componentUpdated = false;
+ }
+
+ public ComponentBuilderImpl(Component component, boolean update) {
+ m_component = component;
+ m_componentUpdated = update;
+ }
+
+ @Override
+ public ComponentBuilderImpl autoConfig(Class<?> clazz, boolean autoConfig) {
+ m_component.setAutoConfig(clazz, autoConfig);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl autoConfig(Class<?> clazz, String instanceName) {
+ m_component.setAutoConfig(clazz, instanceName);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?> iface) {
+ m_serviceNames = new String[] {iface.getName()};
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?> iface, String name, Object value, Object ... rest) {
+ provides(iface);
+ properties(name, value, rest);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?> iface, FluentProperties ... properties) {
+ provides(iface);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?> iface, Dictionary<?,?> properties) {
+ provides(iface);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?>[] ifaces) {
+ m_serviceNames = Stream.of(ifaces).map(c -> c.getName()).toArray(String[]::new);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?>[] ifaces, String name, Object value, Object ... rest) {
+ provides(ifaces);
+ properties(name, value, rest);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?>[] ifaces, FluentProperties ... properties) {
+ provides(ifaces);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(Class<?>[] ifaces, Dictionary<?,?> properties) {
+ provides(ifaces);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String iface) {
+ m_serviceNames = new String[] {iface};
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String iface, String name, Object value, Object ... rest) {
+ provides(iface);
+ properties(name, value, rest);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String iface, FluentProperties ... properties) {
+ provides(iface);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String iface, Dictionary<?,?> properties) {
+ provides(iface);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String[] ifaces) {
+ m_serviceNames = ifaces;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String[] ifaces, String name, Object value, Object ... rest) {
+ provides(ifaces);
+ properties(name, value, rest);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String[] ifaces, FluentProperties ... properties) {
+ provides(ifaces);
+ properties(properties);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl provides(String[] ifaces, Dictionary<?,?> properties) {
+ provides(ifaces);
+ properties(properties);
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ComponentBuilderImpl properties(Dictionary<?, ?> properties) {
+ m_properties = (Dictionary<Object, Object>) properties;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl properties(String name, Object value, Object ... rest) {
+ Objects.nonNull(name);
+ Objects.nonNull(value);
+ Properties props = new Properties();
+ props.put(name, value);
+ if ((rest.length & 1) != 0) {
+ throw new IllegalArgumentException("Invalid number of specified properties (number of arguments must be even).");
+ }
+ for (int i = 0; i < rest.length - 1; i += 2) {
+ String k = rest[i].toString().trim();
+ Object v = rest[i+1];
+ props.put(k, v);
+ }
+ m_properties = props;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl properties(FluentProperties ... properties) {
+ Dictionary<Object, Object> props = new Hashtable<>();
+ Stream.of(properties).forEach(property -> {
+ String name = Helpers.getLambdaParameterName(property, 0);
+ if (name.equals("arg0")) {
+ throw new IllegalArgumentException("arg0 property name not supported");
+ }
+ Object value = property.apply(name);
+ props.put(name, value);
+ });
+ m_properties = props;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl debug(String label) {
+ m_component.setDebug(label);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl autoAdd(boolean autoAdd) {
+ m_autoAdd = autoAdd;
+ return this;
+ }
+
+ public ComponentBuilderImpl autoAdd() {
+ m_autoAdd = true;
+ return this;
+ }
+
+ public boolean isAutoAdd() {
+ return m_autoAdd;
+ }
+
+ @Override
+ public ComponentBuilderImpl impl(Object instance) {
+ m_impl = instance;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl factory(Object factory, String createMethod) {
+ m_factory = factory;
+ m_factoryCreateMethod = createMethod;
+ ensureHasNoFactoryRef();
+ m_hasFactory = true;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl factory(Supplier<?> create) {
+ Objects.nonNull(create);
+ ensureHasNoFactory();
+ m_hasFactoryRef = true;
+ m_factory = new Object() {
+ @SuppressWarnings("unused")
+ public Object create() {
+ return create.get();
+ }
+ };
+ return this;
+ }
+
+ @Override
+ public <U, V> ComponentBuilderImpl factory(Supplier<U> supplier, Function<U, V> create) {
+ Objects.nonNull(supplier);
+ Objects.nonNull(create);
+ ensureHasNoFactory();
+ m_hasFactoryRef = true;
+
+ m_factory = new Object() {
+ @SuppressWarnings("unused")
+ public Object create() {
+ U factoryImpl = supplier.get();
+ return create.apply(factoryImpl);
+ }
+ };
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl factory(Supplier<?> create, Supplier<Object[]> getComposite) {
+ Objects.nonNull(create);
+ Objects.nonNull(getComposite);
+ ensureHasNoFactory();
+ m_hasFactoryRef = true;
+
+ m_factory = new Object() {
+ @SuppressWarnings("unused")
+ public Object create() { // Create Factory instance
+ return create.get();
+ }
+
+ @SuppressWarnings("unused")
+ public Object[] getComposite() { // Create Factory instance
+ return getComposite.get();
+ }
+ };
+ m_factoryHasComposite = true;
+ return this;
+ }
+
+ @Override
+ public <U> ComponentBuilderImpl factory(Supplier<U> factorySupplier, Function<U, ?> factoryCreate, Function<U, Object[]> factoryGetComposite) {
+ Objects.nonNull(factorySupplier);
+ Objects.nonNull(factoryCreate);
+ Objects.nonNull(factoryGetComposite);
+ ensureHasNoFactory();
+ m_hasFactoryRef = true;
+
+ m_factory = new Object() {
+ U m_factoryInstance;
+
+ @SuppressWarnings("unused")
+ public Object create() {
+ m_factoryInstance = factorySupplier.get();
+ return factoryCreate.apply(m_factoryInstance);
+ }
+
+ @SuppressWarnings("unused")
+ public Object[] getComposite() {
+ return factoryGetComposite.apply(m_factoryInstance);
+ }
+ };
+ m_factoryHasComposite = true;
+ return this;
+ }
+
+ public ComponentBuilderImpl composition(String getCompositionMethod) {
+ return composition(null, getCompositionMethod);
+ }
+
+ public ComponentBuilderImpl composition(Object instance, String getCompositionMethod) {
+ m_compositionInstance = instance;
+ m_compositionMethod = getCompositionMethod;
+ return this;
+ }
+
+ public ComponentBuilderImpl composition(Supplier<Object[]> getCompositionMethod) {
+ m_compositionInstance = new Object() {
+ @SuppressWarnings("unused")
+ public Object[] getComposition() {
+ return getCompositionMethod.get();
+ }
+ };
+ m_compositionMethod = "getComposition";
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl withSrv(Class<?> service, String filter) {
+ return withSrv(service, srv->srv.filter(filter));
+ }
+
+ @Override
+ public ComponentBuilderImpl withSrv(Class<?> ... services) {
+ for (Class<?> s : services) {
+ doWithService(s);
+ }
+ return this;
+ }
+
+ private <U> void doWithService(Class<U> service) {
+ ServiceDependencyBuilder<U> dep = new ServiceDependencyBuilderImpl<>(m_component, service);
+ m_dependencyBuilders.add(dep);
+ }
+
+ @Override
+ public <U> ComponentBuilderImpl withSrv(Class<U> service, Consumer<ServiceDependencyBuilder<U>> consumer) {
+ ServiceDependencyBuilder<U> dep = new ServiceDependencyBuilderImpl<>(m_component, service);
+ consumer.accept(dep);
+ m_dependencyBuilders.add(dep);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl withCnf(Consumer<ConfigurationDependencyBuilder> consumer) {
+ ConfigurationDependencyBuilder dep = new ConfigurationDependencyBuilderImpl(m_component);
+ consumer.accept(dep);
+ m_dependencyBuilders.add(dep);
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl withBundle(Consumer<BundleDependencyBuilder> consumer) {
+ BundleDependencyBuilder dep = new BundleDependencyBuilderImpl(m_component);
+ consumer.accept(dep);
+ m_dependencyBuilders.add(dep);
+ return this;
+ }
+
+ @Override
+ public <V> ComponentBuilderImpl withFuture(CompletableFuture<V> future, Consumer<FutureDependencyBuilder<V>> consumer) {
+ FutureDependencyBuilder<V> dep = new CompletableFutureDependencyImpl<>(m_component, future);
+ consumer.accept(dep);
+ m_dependencyBuilders.add(dep);
+ return this;
+ }
+
+ public ComponentBuilderImpl init(String callback) {
+ ensureHasNoLifecycleMethodRefs();
+ m_init = callback;
+ return this;
+ }
+
+ public ComponentBuilderImpl start(String callback) {
+ ensureHasNoLifecycleMethodRefs();
+ m_start = callback;
+ return this;
+ }
+
+ public ComponentBuilderImpl stop(String callback) {
+ ensureHasNoLifecycleMethodRefs();
+ m_stop = callback;
+ return this;
+ }
+
+ public ComponentBuilderImpl destroy(String callback) {
+ ensureHasNoLifecycleMethodRefs();
+ m_destroy = callback;
+ return this;
+ }
+
+ public ComponentBuilderImpl init(Object callbackInstance, String callback) {
+ m_callbackInstance = callbackInstance;
+ return init(callback);
+ }
+
+ public ComponentBuilderImpl start(Object callbackInstance, String callback) {
+ m_callbackInstance = callbackInstance;
+ return start(callback);
+ }
+
+ public ComponentBuilderImpl stop(Object callbackInstance, String callback) {
+ m_callbackInstance = callbackInstance;
+ return stop(callback);
+ }
+
+ public ComponentBuilderImpl destroy(Object callbackInstance, String callback) {
+ m_callbackInstance = callbackInstance;
+ return destroy(callback);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl init(CbConsumer<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(INIT, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl start(CbConsumer<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(START, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl stop(CbConsumer<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(STOP, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl destroy(CbConsumer<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(DESTROY, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl init(CbTypeComponent<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(INIT, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst, component));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl start(CbTypeComponent<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(START, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst, component));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl stop(CbTypeComponent<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(STOP, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst, component));
+ }
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl destroy(CbTypeComponent<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(DESTROY, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst, component));
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl initInstance(Runnable callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(INIT, (inst, component) -> callback.run());
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl startInstance(Runnable callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(START, (inst, component) -> callback.run());
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl stopInstance(Runnable callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(STOP, (inst, component) -> callback.run());
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl destroyInstance(Runnable callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(DESTROY, (inst, component) -> callback.run());
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl initInstance(CbComponent callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(INIT, (inst, component) -> callback.accept(component));
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl startInstance(CbComponent callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(START, (inst, component) -> callback.accept(component));
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl stopInstance(CbComponent callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(STOP, (inst, component) -> callback.accept(component));
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl destroyInstance(CbComponent callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(DESTROY, (inst, component) -> callback.accept(component));
+ }
+ return this;
+ }
+
+ public Component build() {
+ if (m_serviceNames != null) {
+ m_component.setInterface(m_serviceNames, m_properties);
+ }
+
+ if (m_properties != null) {
+ m_component.setServiceProperties(m_properties);
+ }
+
+ if (! m_componentUpdated) { // Don't override impl or set callbacks if component is being updated
+ if (m_impl != null) {
+ m_component.setImplementation(m_impl);
+ m_component.setComposition(m_compositionInstance, m_compositionMethod);
+ } else {
+ Objects.nonNull(m_factory);
+ if (m_hasFactoryRef) {
+ m_component.setFactory(m_factory, "create");
+ if (m_factoryHasComposite) {
+ m_component.setComposition(m_factory, "getComposite");
+ }
+ } else {
+ m_component.setFactory(m_factory, m_factoryCreateMethod);
+ }
+ }
+
+ if (m_refs.size() > 0) {
+ setLifecycleMethodRefs();
+ } else if (hasLifecleMethods()) {
+ m_component.setCallbacks(m_callbackInstance, m_init, m_start, m_stop, m_destroy);
+ }
+ }
+
+ if (m_dependencyBuilders.size() > 0) {
+ // add atomically in case we are building some component dependencies from a component init method.
+ // We first transform the list of builders into a stream of built Dependencies, then we collect the result
+ // to an array of Dependency[].
+ m_component.add(m_dependencyBuilders.stream().map(builder -> builder.build()).toArray(Dependency[]::new));
+ }
+ return m_component;
+ }
+
+ private boolean hasLifecleMethods() {
+ return m_init != null || m_start != null || m_stop != null || m_destroy != null;
+ }
+
+ private boolean hasLifecleMethodRefs() {
+ return m_refs.size() > 0;
+ }
+
+ private void ensureHasNoLifecycleMethods() {
+ if (hasLifecleMethods()) {
+ throw new IllegalStateException("Can't mix method references and name names for lifecycle callbacks");
+ }
+ }
+
+ private void ensureHasNoLifecycleMethodRefs() {
+ if (hasLifecleMethodRefs()) {
+ throw new IllegalStateException("Can't mix method references and name names for lifecycle callbacks");
+ }
+ }
+
+ protected <U> ComponentBuilderImpl setInstanceCallbackRef(ComponentCallback cbType, MethodRef<U> ref) {
+ ensureHasNoLifecycleMethods();
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component) -> {
+ ref.accept(null, component);
+ });
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <U> ComponentBuilderImpl setComponentCallbackRef(ComponentCallback cbType, Class<U> type, MethodRef<U> callback) {
+ ensureHasNoLifecycleMethods();
+ if (type.equals(Object.class)) {
+ throw new IllegalStateException("callback does not seam to be one from the possible component implementation classes");
+ }
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + callback + " does not match any available component impl classes."));
+ callback.accept((U) componentImpl, component);
+ });
+ return this;
+ }
+
+ @SuppressWarnings("unused")
+ private void setLifecycleMethodRefs() {
+ Object cb = new Object() {
+ void init(Component comp) {
+ invokeLfcleCallbacks(ComponentCallback.INIT, comp);
+ }
+
+ void start(Component comp) {
+ invokeLfcleCallbacks(ComponentCallback.START, comp);
+ }
+
+ void stop(Component comp) {
+ invokeLfcleCallbacks(ComponentCallback.STOP, comp);
+ }
+
+ void destroy(Component comp) {
+ invokeLfcleCallbacks(ComponentCallback.DESTROY, comp);
+ }
+ };
+ m_component.setCallbacks(cb, "init", "start", "stop", "destroy");
+ }
+
+ private void invokeLfcleCallbacks(ComponentCallback cbType, Component component) {
+ m_refs.computeIfPresent(cbType, (k, mrefs) -> {
+ mrefs.forEach(mref -> mref.accept(null, component));
+ return mrefs;
+ });
+ }
+
+ private void ensureHasNoFactoryRef() {
+ if (m_hasFactoryRef) {
+ throw new IllegalStateException("Can't mix factory method name and factory method reference");
+ }
+ }
+
+ private void ensureHasNoFactory() {
+ if (m_hasFactory) {
+ throw new IllegalStateException("Can't mix factory method name and factory method reference");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java
new file mode 100644
index 0000000..89f48c6
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java
@@ -0,0 +1,162 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ConfigurationDependency;
+import org.apache.felix.dm.lambda.ConfigurationDependencyBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeDictionary;
+
+public class ConfigurationDependencyBuilderImpl implements ConfigurationDependencyBuilder {
+ private String m_pid;
+ private boolean m_propagate;
+ private final Component m_component;
+ private String m_updateMethodName;
+ private Object m_updateCallbackInstance;
+ private boolean m_hasMethodRefs;
+ private boolean m_hasReflectionCallback;
+ private final List<MethodRef<Object>> m_refs = new ArrayList<>();
+ private boolean m_hasComponentCallbackRefs;
+ private boolean m_needsInstance = false;
+
+ @FunctionalInterface
+ interface MethodRef<I> {
+ public void accept(I instance, Component c, Dictionary<String, Object> props);
+ }
+
+ public ConfigurationDependencyBuilderImpl(Component component) {
+ m_component = component;
+ }
+
+ @Override
+ public ConfigurationDependencyBuilder pid(String pid) {
+ m_pid = pid;
+ return this;
+ }
+
+ @Override
+ public ConfigurationDependencyBuilder pid(Class<?> pidClass) {
+ m_pid = pidClass.getName();
+ return this;
+ }
+
+ @Override
+ public ConfigurationDependencyBuilder propagate() {
+ m_propagate = true;
+ return this;
+ }
+
+ @Override
+ public ConfigurationDependencyBuilder propagate(boolean propagate) {
+ m_propagate = propagate;
+ return this;
+ }
+
+ public ConfigurationDependencyBuilder cb(String update) {
+ checkHasNoMethodRefs();
+ m_hasReflectionCallback = true;
+ m_updateMethodName = update;
+ return this;
+ }
+
+ public ConfigurationDependencyBuilder cbi(Object callbackInstance, String update) {
+ m_updateCallbackInstance = callbackInstance;
+ cb(update);
+ return this;
+ }
+
+ public ConfigurationDependencyBuilder needsInstance(boolean needsInstance) {
+ m_needsInstance = needsInstance;
+ return this;
+ }
+
+ @Override
+ public <T> ConfigurationDependencyBuilder cb(CbTypeDictionary<T> callback) {
+ Class<T> type = Helpers.getLambdaArgType(callback, 0);
+ return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((T) instance, props); });
+ }
+
+ @Override
+ public <T> ConfigurationDependencyBuilder cb(CbTypeComponentDictionary<T> callback) {
+ Class<T> type = Helpers.getLambdaArgType(callback, 0);
+ return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((T) instance, component, props); });
+ }
+
+ @Override
+ public ConfigurationDependencyBuilder cbi(CbDictionary callback) {
+ return setInstanceCallbackRef((instance, component, props) -> { callback.accept(props); });
+ }
+
+ @Override
+ public ConfigurationDependencyBuilder cbi(CbComponentDictionary callback) {
+ return setInstanceCallbackRef((instance, component, props) -> { callback.accept(component, props); });
+ }
+
+ @Override
+ public ConfigurationDependency build() {
+ ConfigurationDependency dep = m_component.getDependencyManager().createConfigurationDependency();
+ Objects.nonNull(m_pid);
+ dep.setPid(m_pid);
+ dep.setPropagate(m_propagate);
+ if (m_updateMethodName != null) {
+ if (m_updateCallbackInstance != null) {
+ dep.setCallback(m_updateCallbackInstance, m_updateMethodName, m_needsInstance);
+ } else {
+ dep.setCallback(m_updateMethodName);
+ }
+ } else if (m_refs.size() > 0) {
+ // setup an internal callback object. When config is updated, we have to call each registered
+ // method references.
+ // Notice that we need the component to be instantiated in case there is a mref on one of the component instances (unbound method ref), or is used
+ // called "needsInstance(true)".
+ dep.setCallback(new Object() {
+ @SuppressWarnings("unused")
+ void updated(Component comp, Dictionary<String, Object> props) {
+ m_refs.forEach(mref -> mref.accept(null, comp, props));
+ }
+ }, "updated", m_hasComponentCallbackRefs||m_needsInstance);
+ }
+ return dep;
+ }
+
+ private <T> ConfigurationDependencyBuilder setInstanceCallbackRef(MethodRef<T> ref) {
+ checkHasNoReflectionCallbacks();
+ m_hasMethodRefs = true;
+ m_refs.add((instance, component, props) -> ref.accept(null, component, props));
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <T> ConfigurationDependencyBuilder setComponentCallbackRef(Class<T> type, MethodRef<T> ref) {
+ checkHasNoReflectionCallbacks();
+ m_hasMethodRefs = true;
+ m_hasComponentCallbackRefs = true;
+ m_refs.add((instance, component, props) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
+ ref.accept((T) componentImpl, component, props);
+ });
+ return this;
+ }
+
+ private void checkHasNoMethodRefs() {
+ if (m_hasMethodRefs) {
+ throw new IllegalStateException("Can't mix method references with reflection based callbacks");
+ }
+ }
+
+ private void checkHasNoReflectionCallbacks() {
+ if (m_hasReflectionCallback) {
+ throw new IllegalStateException("Can't mix method references with reflection based callbacks");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java
new file mode 100644
index 0000000..c3ee095
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java
@@ -0,0 +1,166 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.ComponentBuilder;
+import org.apache.felix.dm.lambda.FactoryPidAdapterBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentDictionary;
+import org.apache.felix.dm.lambda.callbacks.CbTypeDictionary;
+
+public class FactoryPidAdapterBuilderImpl implements AdapterBase<FactoryPidAdapterBuilder>, FactoryPidAdapterBuilder {
+ private String m_factoryPid;
+ private boolean m_propagate;
+ private final DependencyManager m_dm;
+ private boolean m_autoAdd = true;
+ private String m_updateMethodName;
+ private Object m_updateCallbackInstance;
+ private boolean m_hasMethodRefs;
+ private boolean m_hasReflectionCallback;
+ private Consumer<ComponentBuilder<?>> m_compBuilder = (componentBuilder -> {});
+ private final List<MethodRef<Object>> m_refs = new ArrayList<>();
+
+ @FunctionalInterface
+ interface MethodRef<I> {
+ public void accept(I instance, Component c, Dictionary<String, Object> props);
+ }
+
+ public FactoryPidAdapterBuilderImpl(DependencyManager dm) {
+ m_dm = dm;
+ }
+
+ public void andThenBuild(Consumer<ComponentBuilder<?>> builder) {
+ m_compBuilder = m_compBuilder.andThen(builder);
+ }
+
+ @Override
+ public FactoryPidAdapterBuilderImpl autoAdd(boolean autoAdd) {
+ m_autoAdd = autoAdd;
+ return this;
+ }
+
+ public boolean isAutoAdd() {
+ return m_autoAdd;
+ }
+
+ @Override
+ public FactoryPidAdapterBuilder factoryPid(String pid) {
+ m_factoryPid = pid;
+ return this;
+ }
+
+ @Override
+ public FactoryPidAdapterBuilder factoryPid(Class<?> pidClass) {
+ m_factoryPid = pidClass.getName();
+ return this;
+ }
+
+ @Override
+ public FactoryPidAdapterBuilder propagate() {
+ m_propagate = true;
+ return this;
+ }
+
+ @Override
+ public FactoryPidAdapterBuilder propagate(boolean propagate) {
+ m_propagate = propagate;
+ return this;
+ }
+
+ public FactoryPidAdapterBuilder cb(String update) {
+ checkHasNoMethodRefs();
+ m_hasReflectionCallback = true;
+ m_updateMethodName = update;
+ return this;
+ }
+
+ public FactoryPidAdapterBuilder cb(Object callbackInstance, String update) {
+ cb(update);
+ m_updateCallbackInstance = callbackInstance;
+ return this;
+ }
+
+ @Override
+ public <U> FactoryPidAdapterBuilder cb(CbTypeDictionary<U> callback) {
+ Class<U> type = Helpers.getLambdaArgType(callback, 0);
+ return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((U) instance, props); });
+ }
+
+ @Override
+ public <U> FactoryPidAdapterBuilder cb(CbTypeComponentDictionary<U> callback) {
+ Class<U> type = Helpers.getLambdaArgType(callback, 0);
+ return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((U) instance, component, props); });
+ }
+
+ @Override
+ public FactoryPidAdapterBuilder cbi(CbDictionary callback) {
+ return setInstanceCallbackRef((instance, component, props) -> { callback.accept(props); });
+ }
+
+ @Override
+ public FactoryPidAdapterBuilder cbi(CbComponentDictionary callback) {
+ return setInstanceCallbackRef((instance, component, props) -> { callback.accept(component, props); });
+ }
+
+ @Override
+ public Component build() {
+ Objects.nonNull(m_factoryPid);
+ Component c = null;
+
+ if (m_hasMethodRefs) {
+ Object wrapCallback = new Object() {
+ @SuppressWarnings("unused")
+ public void updated(Component comp, Dictionary<String, Object> conf) {
+ m_refs.forEach(mref -> mref.accept(null, comp, conf));
+ }
+ };
+ c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, "updated", m_propagate, wrapCallback);
+ } else {
+ c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, m_updateMethodName, m_propagate, m_updateCallbackInstance);
+ }
+ ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false);
+ m_compBuilder.accept (cb);
+ return cb.build();
+ }
+
+ private <U> FactoryPidAdapterBuilder setInstanceCallbackRef(MethodRef<U> ref) {
+ checkHasNoReflectionCallbacks();
+ m_hasMethodRefs = true;
+ m_refs.add((instance, component, props) -> ref.accept(null, component, props));
+ return this;
+ }
+
+ @SuppressWarnings("unchecked")
+ private <U> FactoryPidAdapterBuilder setComponentCallbackRef(Class<U> type, MethodRef<U> ref) {
+ checkHasNoReflectionCallbacks();
+ m_hasMethodRefs = true;
+ m_refs.add((instance, component, props) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
+ ref.accept((U) componentImpl, component, props);
+ });
+ return this;
+ }
+
+ private void checkHasNoMethodRefs() {
+ if (m_hasMethodRefs) {
+ throw new IllegalStateException("Can't mix method references with reflection based callbacks");
+ }
+ }
+
+ private void checkHasNoReflectionCallbacks() {
+ if (m_hasReflectionCallback) {
+ throw new IllegalStateException("Can't mix method references with reflection based callbacks");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java
new file mode 100644
index 0000000..50eb73c
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java
@@ -0,0 +1,147 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.lang.invoke.SerializedLambda;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.lambda.callbacks.SerializableLambda;
+
+/**
+ * Various helper methods related to generics and lambda expressions.
+ */
+public class Helpers {
+ private final static Pattern LAMBDA_INSTANCE_METHOD_TYPE = Pattern.compile("(L[^;]+)+");
+
+ /**
+ * Gets the class name of a given object.
+ * @param obj the object whose class has to be returned.
+ */
+ public static Class<?> getClass(Object obj) {
+ Class<?> clazz = obj.getClass();
+ if (Proxy.isProxyClass(clazz)) {
+ return Proxy.getProxyClass(clazz.getClassLoader(), clazz);
+ }
+ return clazz;
+ }
+
+ /**
+ * Extracts the type of a given generic lambda parameter.
+ * Example: for "BiConsumer<String, Integer>", and with genericParamIndex=0, this method returns java.lang.String class.
+ *
+ * @param lambda a lambda expression, which must extends @link {@link SerializableLambda} interface.
+ * @param genericParamIndex the index of a given lambda generic parameter.
+ * @return the type of the lambda generic parameter that corresponds to the <code>genericParamIndex</code>
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Class<T> getLambdaArgType(SerializableLambda lambda, int genericParamIndex) {
+ String[] lambdaParams = getGenericTypeStrings(lambda);
+ Class<?> clazz;
+ try {
+ clazz = lambda.getClass().getClassLoader().loadClass(lambdaParams[genericParamIndex]);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Can't load class " + lambdaParams[genericParamIndex]);
+ }
+ return (Class<T>) clazz;
+ }
+
+ /**
+ * Extracts the first parameter of a lambda.
+ */
+ public static String getLambdaParameterName(SerializableLambda lambda, int index) {
+ SerializedLambda serialized = getSerializedLambda(lambda);
+ Method m = getLambdaMethod(serialized, lambda.getClass().getClassLoader());
+ Parameter p = m.getParameters()[index];
+
+ if (Objects.equals("arg0", p.getName())) {
+ throw new IllegalStateException("Can'f find lambda method name (Please check you are using javac -parameters option).");
+ }
+ return p.getName();
+ }
+
+ /**
+ * Returns the SerializedObject of a given lambda.
+ */
+ private static SerializedLambda getSerializedLambda(SerializableLambda lambda) {
+ if (lambda == null) {
+ throw new IllegalArgumentException();
+ }
+
+ for (Class<?> clazz = lambda.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+ try {
+ Method replaceMethod = clazz.getDeclaredMethod("writeReplace");
+ replaceMethod.setAccessible(true);
+ Object serializedForm = replaceMethod.invoke(lambda);
+
+ if (serializedForm instanceof SerializedLambda) {
+ return (SerializedLambda) serializedForm;
+ }
+ }
+ catch (NoSuchMethodException e) {
+ // fall through the loop and try the next class
+ }
+ catch (Throwable t) {
+ throw new RuntimeException("Error while extracting serialized lambda", t);
+ }
+ }
+
+ throw new RuntimeException("writeReplace method not found");
+ }
+
+ /**
+ * Finds a composite
+ * @param component
+ * @param type
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public static <U> U findCompositeInstance(Component component, Class<U> type) {
+ U instance = (U) Stream.of(component.getInstances())
+ .filter(inst -> Objects.equals(Helpers.getClass(inst), type))
+ .findFirst()
+ .orElseThrow(() -> new RuntimeException("Did not find a component instance matching type " + type));
+ return instance;
+ }
+
+ /**
+ * Extracts the actual types of all lambda generic parameters.
+ * Example: for "BiConsumer<String, Integer>", this method returns ["java.lang.String", "java.lang.Integer"].
+ */
+ private static String[] getGenericTypeStrings(SerializableLambda lambda) {
+ // The only portable way to get the actual lambda generic parameters can be done using SerializedLambda.
+ SerializedLambda sl = getSerializedLambda(lambda);
+ String lambdaMethodType = sl.getInstantiatedMethodType();
+ Matcher m = LAMBDA_INSTANCE_METHOD_TYPE.matcher(lambdaMethodType);
+ List<String> results = new ArrayList<>();
+ while (m.find()) {
+ results.add(m.group().substring(1).replace("/", "."));
+ }
+ return results.toArray(new String[0]);
+ }
+
+ /**
+ * Extracts the actual java method from a given lambda.
+ */
+ private static Method getLambdaMethod(SerializedLambda lambda, ClassLoader loader) {
+ String implClassName = lambda.getImplClass().replace('/', '.');
+ Class<?> implClass;
+ try {
+ implClass = loader.loadClass(implClassName);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Lambda Method not found (can not instantiate class " + implClassName);
+ }
+
+ return Stream.of(implClass.getDeclaredMethods())
+ .filter(method -> Objects.equals(method.getName(), lambda.getImplMethodName()))
+ .findFirst()
+ .orElseThrow(() -> new RuntimeException("Lambda Method not found"));
+ }
+
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java
new file mode 100644
index 0000000..4e14d9a
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java
@@ -0,0 +1,94 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Maps a ServiceReference to a Dictionary.
+ */
+public class SRefAsDictionary extends Dictionary<String, Object> {
+ private final ServiceReference<?> m_ref;
+ private volatile int m_size = -1;
+
+ public SRefAsDictionary(ServiceReference<?> ref) {
+ m_ref = ref;
+ }
+
+ @Override
+ public Object get(Object key) {
+ return m_ref.getProperty(key.toString());
+ }
+
+ @Override
+ public int size() {
+ return m_size != -1 ? m_size : (m_size = m_ref.getPropertyKeys().length);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override
+ public Enumeration<String> keys() {
+ return Collections.enumeration(Arrays.asList(m_ref.getPropertyKeys()));
+ }
+
+ @Override
+ public Enumeration<Object> elements() {
+ final String[] keys = m_ref.getPropertyKeys();
+
+ return new Enumeration<Object>() {
+ int m_index = 0;
+
+ @Override
+ public boolean hasMoreElements() {
+ return m_index < keys.length;
+ }
+
+ @Override
+ public Object nextElement() {
+ if (m_index >= keys.length) {
+ throw new NoSuchElementException();
+ }
+ return m_ref.getProperty(keys[m_index ++]);
+ }
+ };
+ }
+
+ @Override
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String toString() {
+ int max = size() - 1;
+ if (max == -1)
+ return "{}";
+
+ StringBuilder sb = new StringBuilder();
+ String[] keys = m_ref.getPropertyKeys();
+ sb.append('{');
+ for (int i = 0; ; i++) {
+ String key = keys[i];
+ Object value = m_ref.getProperty(key);
+ sb.append(key);
+ sb.append('=');
+ sb.append(value == this ? "(this Dictionary)" : value.toString());
+
+ if (i == max)
+ return sb.append('}').toString();
+ sb.append(", ");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java
new file mode 100644
index 0000000..40f411a
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java
@@ -0,0 +1,84 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Maps a ServiceReference to a Map.
+ */
+public class SRefAsMap extends AbstractMap<String, Object> {
+ private final ServiceReference<?> m_ref;
+
+ public SRefAsMap(ServiceReference<?> ref) {
+ m_ref = ref;
+ }
+
+ public Object get(Object key) {
+ return m_ref.getProperty(key.toString());
+ }
+
+ @Override
+ public Set<Entry<String, Object>> entrySet() {
+ return new AbstractSet<Entry<String, Object>>() {
+ @Override
+ public Iterator<Entry<String, Object>> iterator() {
+ final Enumeration<String> e = Collections.enumeration(Arrays.asList(m_ref.getPropertyKeys()));
+
+ return new Iterator<Entry<String, Object>>() {
+ private String key;
+
+ public boolean hasNext() {
+ return e.hasMoreElements();
+ }
+
+ public Entry<String, Object> next() {
+ key = e.nextElement();
+ return new KeyEntry(key);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return m_ref.getPropertyKeys().length;
+ }
+ };
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ class KeyEntry implements Map.Entry<String, Object> {
+ private final String key;
+
+ KeyEntry(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Object getValue() {
+ return m_ref.getProperty(key);
+ }
+
+ public Object setValue(Object value) {
+ return SRefAsMap.this.put(key, value);
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java
new file mode 100644
index 0000000..01d6270
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java
@@ -0,0 +1,83 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.ComponentBuilder;
+import org.apache.felix.dm.lambda.ServiceAdapterBuilder;
+
+public class ServiceAdapterBuilderImpl<T> extends ServiceCallbacksBuilderImpl<T, ServiceAdapterBuilder<T>> implements
+ AdapterBase<ServiceAdapterBuilder<T>>, ServiceAdapterBuilder<T>
+{
+ private final Class<T> m_adapteeType;
+ private String m_adapteeFilter;
+ private boolean m_propagate = true;
+ private final DependencyManager m_dm;
+ private boolean m_autoAdd = true;
+ private Consumer<ComponentBuilder<?>> m_compBuilder = (componentBuilder -> {});
+
+ public ServiceAdapterBuilderImpl(DependencyManager dm, Class<T> adapterType) {
+ super(adapterType);
+ m_dm = dm;
+ m_adapteeType = adapterType;
+ }
+
+ @Override
+ public void andThenBuild(Consumer<ComponentBuilder<?>> after) {
+ m_compBuilder = m_compBuilder.andThen(after);
+ }
+
+ @Override
+ public ServiceAdapterBuilderImpl<T> autoAdd(boolean autoAdd) {
+ m_autoAdd = autoAdd;
+ return this;
+ }
+
+ public ServiceAdapterBuilderImpl<T> autoAdd() {
+ m_autoAdd = true;
+ return this;
+ }
+
+ public boolean isAutoAdd() {
+ return m_autoAdd;
+ }
+
+ @Override
+ public ServiceAdapterBuilder<T> filter(String adapteeFilter) {
+ m_adapteeFilter = adapteeFilter;
+ return this;
+ }
+
+ @Override
+ public ServiceAdapterBuilder<T> propagate(boolean propagate) {
+ m_propagate = propagate;
+ return this;
+ }
+
+ @Override
+ public Component build() {
+ Objects.nonNull(m_adapteeFilter);
+
+ String add = getAdded(), change = getChanged(), remove = getRemoved(), swap = getSwapped();
+ Object cbInstance = getCallbackInstance();
+
+ if (hasRefs()) {
+ // if some method references have been set, use our own callback proxy to redispatch events to method refs.
+ cbInstance = createCallbackInstance();
+ add = "add";
+ change = "change";
+ remove = "remove";
+ swap = m_swapRefs.size() > 0 ? "swap" : null;
+ }
+
+ Component c = m_dm.createAdapterService
+ (m_adapteeType, m_adapteeFilter, getAutoConfigField(), cbInstance, add, change, remove, swap, m_propagate);
+
+ ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false);
+ // m_compBuilder is a composed consumer that calls in sequence all necessary component builder methods.
+ m_compBuilder.accept (cb);
+ return cb.build();
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java
new file mode 100644
index 0000000..48274f6
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java
@@ -0,0 +1,86 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.lambda.ComponentBuilder;
+import org.apache.felix.dm.lambda.ServiceAspectBuilder;
+
+public class ServiceAspectBuilderImpl<T> extends ServiceCallbacksBuilderImpl<T, ServiceAspectBuilder<T>> implements
+ AdapterBase<ServiceAspectBuilder<T>>, ServiceAspectBuilder<T>
+{
+ private final DependencyManager m_dm;
+ private final Class<T> m_aspectType;
+ private String m_aspectFilter;
+ private int m_aspectRanking;
+ private boolean m_autoAdd = true;
+ private Consumer<ComponentBuilder<?>> m_compBuilder = (componentBuilder -> {});
+
+ public ServiceAspectBuilderImpl(DependencyManager dm, Class<T> aspectType) {
+ super(aspectType);
+ m_dm = dm;
+ m_aspectType = aspectType;
+ }
+
+ @Override
+ public void andThenBuild(Consumer<ComponentBuilder<?>> after) {
+ m_compBuilder = m_compBuilder.andThen(after);
+ }
+
+ @Override
+ public ServiceAspectBuilderImpl<T> autoAdd(boolean autoAdd) {
+ m_autoAdd = autoAdd;
+ return this;
+ }
+
+ public boolean isAutoAdd() {
+ return m_autoAdd;
+ }
+
+ @Override
+ public ServiceAspectBuilder<T> filter(String aspectFilter) {
+ m_aspectFilter = aspectFilter;
+ return this;
+ }
+
+ @Override
+ public ServiceAspectBuilder<T> rank(int ranking) {
+ m_aspectRanking = ranking;
+ return this;
+ }
+
+ @Override
+ public Component build() {
+ Objects.nonNull(m_aspectType);
+
+ if (getAutoConfigField() != null && (hasRefs()|| hasCallbacks())) {
+ throw new IllegalStateException("Can't mix autoConfig fields and aspect callbacks.");
+ }
+
+ Component c = null;
+ if (getAutoConfigField() != null) {
+ c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking, getAutoConfigField());
+ } else if (hasRefs()) {
+ Object cbInstance = createCallbackInstance();
+ String add = "add";
+ String change = "change";
+ String remove = "remove";
+ String swap = m_swapRefs.size() > 0 ? "swap" : null;
+ c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking, cbInstance, add, change, remove, swap);
+ } else if (hasCallbacks()) {
+ String add = getAdded();
+ String change = getChanged();
+ String remove = getRemoved();
+ String swap = getSwapped();
+ c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking, add, change, remove, swap);
+ } else {
+ c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking);
+ }
+ ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false);
+ // m_compBuilder is a composed consumer that calls in sequence all necessary component builder methods.
+ m_compBuilder.accept (cb);
+ return cb.build();
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceCallbacksBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceCallbacksBuilderImpl.java
new file mode 100644
index 0000000..33188ac
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceCallbacksBuilderImpl.java
@@ -0,0 +1,651 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.lambda.ServiceCallbacksBuilder;
+import org.apache.felix.dm.lambda.callbacks.CbComponent;
+import org.apache.felix.dm.lambda.callbacks.CbComponentRef;
+import org.apache.felix.dm.lambda.callbacks.CbComponentRefService;
+import org.apache.felix.dm.lambda.callbacks.CbComponentRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbComponentService;
+import org.apache.felix.dm.lambda.callbacks.CbComponentServiceService;
+import org.apache.felix.dm.lambda.callbacks.CbRef;
+import org.apache.felix.dm.lambda.callbacks.CbRefService;
+import org.apache.felix.dm.lambda.callbacks.CbRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbService;
+import org.apache.felix.dm.lambda.callbacks.CbServiceDict;
+import org.apache.felix.dm.lambda.callbacks.CbServiceMap;
+import org.apache.felix.dm.lambda.callbacks.CbServiceService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponent;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentRef;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeComponentServiceService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeRef;
+import org.apache.felix.dm.lambda.callbacks.CbTypeRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeRefServiceRefService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeService;
+import org.apache.felix.dm.lambda.callbacks.CbTypeServiceDict;
+import org.apache.felix.dm.lambda.callbacks.CbTypeServiceMap;
+import org.apache.felix.dm.lambda.callbacks.CbTypeServiceService;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Service Dependency Callback management.
+ *
+ * @param <S> the type of the service dependency
+ * @param <B> the type of the sub-classes which may extend this class
+ */
+@SuppressWarnings({"unchecked", "unused"})
+public class ServiceCallbacksBuilderImpl<S, B extends ServiceCallbacksBuilder<S, B>> implements ServiceCallbacksBuilder<S, B> {
+ protected boolean m_autoConfig = true;
+ protected boolean m_autoConfigInvoked = false;
+ protected String m_autoConfigField;
+ protected Object m_callbackInstance;
+ protected String m_added;
+ protected String m_changed;
+ protected String m_removed;
+ protected String m_swapped;
+ protected final Class<S> m_serviceClass;
+
+ enum Cb {
+ ADD,
+ CHG,
+ REM
+ };
+
+ /**
+ * List of service (add/change/remove) callbacks.
+ */
+ protected final Map<Cb, List<MethodRef<Object, S>>> m_refs = new HashMap<>();
+
+ /**
+ * List of swap callbacks
+ */
+ protected final List<SwapMethodRef<?, S>> m_swapRefs = new ArrayList<>();
+
+ /**
+ * This interface (lambda) is called when we want to invoke a method reference. the lambda is called with all necessary service dependency
+ * informations.
+ *
+ * When the lambda is called, it will invoke the proper callback on the given component instance.
+ *
+ * @param <I> type of a component instance
+ * @param <T> service dependency type
+ */
+ @FunctionalInterface
+ interface MethodRef<I, S> {
+ public void accept(I instance, Component c, ServiceReference<S> ref, S service);
+ }
+
+ /**
+ * This interface (lambda) is called when we want to invoke a swap method reference. the lambda is called with all necessary swap info.
+ * When the lambda is called, it will invoke the proper swap callback on the given component instance.
+ *
+ * @param <I> type of a component instance
+ * @param <T> service dependency type
+ */
+ @FunctionalInterface
+ interface SwapMethodRef<I, S> {
+ public void accept(I instance, Component c, ServiceReference<S> oldRef, S oldService, ServiceReference<S> newRef, S newService);
+ }
+
+ public ServiceCallbacksBuilderImpl(Class<S> serviceClass) {
+ m_serviceClass = serviceClass;
+ }
+
+ public B autoConfig() {
+ autoConfig(true);
+ return (B) this;
+ }
+
+ public B autoConfig(String field) {
+ m_autoConfigField = field;
+ m_autoConfigInvoked = true;
+ return (B) this;
+ }
+
+ public B autoConfig(boolean autoConfig) {
+ m_autoConfig = autoConfig;
+ m_autoConfigInvoked = true;
+ return (B) this;
+ }
+
+ public B cb(String ... callbacks) {
+ return cbi(null, callbacks);
+ }
+
+ public B cbi(Object callbackInstance, String ... callbacks) {
+ Objects.nonNull(callbacks);
+ switch (callbacks.length) {
+ case 1:
+ cb(callbackInstance, callbacks[0], null, null, null);
+ break;
+
+ case 2:
+ cb(callbackInstance, callbacks[0], null, callbacks[1], null);
+ break;
+
+ case 3:
+ cb(callbackInstance, callbacks[0], callbacks[1], callbacks[2], null);
+ break;
+
+ case 4:
+ cb(callbackInstance, callbacks[0], callbacks[1], callbacks[2], callbacks[3]);
+ break;
+
+ default:
+ throw new IllegalArgumentException("wrong number of arguments: " + callbacks.length + ". " +
+ "Possible arguments: [add], [add, remove], [add, change, remove], or [add, change, remove, swap]");
+ }
+ return (B) this;
+ }
+
+ private B cb(Object callbackInstance, String added, String changed, String removed, String swapped) {
+ requiresNoMethodRefs();
+ m_callbackInstance = callbackInstance;
+ m_added = added != null ? added : m_added;
+ m_changed = changed != null ? changed : m_changed;
+ m_removed = removed != null ? removed : m_removed;
+ m_swapped = swapped != null ? swapped : m_swapped;
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeService<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeService<T, S> add, CbTypeService<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeService<T, S> add, CbTypeService<T, S> change, CbTypeService<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, srv));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, srv));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, srv));
+ return (B) this;
+ }
+
+ public B cbi(CbService<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbService<S> add, CbService<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbService<S> add, CbService<S> change, CbService<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(srv));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(srv));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(srv));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeServiceMap<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeServiceMap<T, S> add, CbTypeServiceMap<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeServiceMap<T, S> add, CbTypeServiceMap<T, S> change, CbTypeServiceMap<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, srv, new SRefAsMap(ref)));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, srv, new SRefAsMap(ref)));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, srv, new SRefAsMap(ref)));
+ return (B) this;
+ }
+
+ public B cbi(CbServiceMap<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbServiceMap<S> add, CbServiceMap<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbServiceMap<S> add, CbServiceMap<S> change, CbServiceMap<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(srv, new SRefAsMap(ref)));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(srv, new SRefAsMap(ref)));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(srv, new SRefAsMap(ref)));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeServiceDict<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeServiceDict<T, S> add, CbTypeServiceDict<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeServiceDict<T, S> add, CbTypeServiceDict<T, S> change, CbTypeServiceDict<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, srv, new SRefAsDictionary(ref)));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, srv, new SRefAsDictionary(ref)));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, srv, new SRefAsDictionary(ref)));
+ return (B) this;
+ }
+
+ public B cbi(CbServiceDict<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbServiceDict<S> add, CbServiceDict<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbServiceDict<S> add, CbServiceDict<S> change, CbServiceDict<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(srv, new SRefAsDictionary(ref)));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(srv, new SRefAsDictionary(ref)));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(srv, new SRefAsDictionary(ref)));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeRefService<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeRefService<T, S> add, CbTypeRefService<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeRefService<T, S> add, CbTypeRefService<T, S> change, CbTypeRefService<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, ref, srv));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, ref, srv));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, ref, srv));
+ return (B) this;
+ }
+
+ public B cbi(CbRefService<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbRefService<S> add, CbRefService<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbRefService<S> add, CbRefService<S> change, CbRefService<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(ref, srv));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(ref, srv));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(ref, srv));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeRef<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeRef<T, S> add, CbTypeRef<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeRef<T, S> add, CbTypeRef<T, S> change, CbTypeRef<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, ref));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, ref));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, ref));
+ return (B) this;
+ }
+
+ public B cbi(CbRef<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbRef<S> add, CbRef<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbRef<S> add, CbRef<S> change, CbRef<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(ref));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(ref));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(ref));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeComponent<T> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeComponent<T> add, CbTypeComponent<T> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeComponent<T> add, CbTypeComponent<T> change, CbTypeComponent<T> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, comp));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, comp));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, comp));
+ return (B) this;
+ }
+
+ public B cbi(CbComponent add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbComponent add, CbComponent remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbComponent add, CbComponent change, CbComponent remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(comp));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(comp));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(comp));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeComponentRef<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeComponentRef<T, S> add, CbTypeComponentRef<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeComponentRef<T, S> add, CbTypeComponentRef<T, S> change, CbTypeComponentRef<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, comp, ref));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, comp, ref));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, comp, ref));
+ return (B) this;
+ }
+
+ public B cbi(CbComponentRef<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbComponentRef<S> add, CbComponentRef<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbComponentRef<S> add, CbComponentRef<S> change, CbComponentRef<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(comp, ref));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(comp, ref));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(comp, ref));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeComponentService<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeComponentService<T, S> add, CbTypeComponentService<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeComponentService<T, S> add, CbTypeComponentService<T, S> change, CbTypeComponentService<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, comp, srv));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, comp, srv));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, comp, srv));
+ return (B) this;
+ }
+
+ public B cbi(CbComponentService<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbComponentService<S> add, CbComponentService<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbComponentService<S> add, CbComponentService<S> change, CbComponentService<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(comp, srv));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(comp, srv));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(comp, srv));
+ return (B) this;
+ }
+
+ public <T> B cb(CbTypeComponentRefService<T, S> add) {
+ return cb(add, null, null);
+ }
+
+ public <T> B cb(CbTypeComponentRefService<T, S> add, CbTypeComponentRefService<T, S> remove) {
+ return cb(add, null, remove);
+ }
+
+ public <T> B cb(CbTypeComponentRefService<T, S> add, CbTypeComponentRefService<T, S> change, CbTypeComponentRefService<T, S> remove) {
+ if (add != null)
+ setComponentCallbackRef(Cb.ADD, Helpers.getLambdaArgType(add, 0), (inst, comp, ref, srv) -> add.accept((T) inst, comp, ref, srv));
+ if (change != null)
+ setComponentCallbackRef(Cb.CHG, Helpers.getLambdaArgType(change, 0), (inst, comp, ref, srv) -> change.accept((T) inst, comp, ref, srv));
+ if (remove != null)
+ setComponentCallbackRef(Cb.REM, Helpers.getLambdaArgType(remove, 0), (inst, comp, ref, srv) -> remove.accept((T) inst, comp, ref, srv));
+ return (B) this;
+ }
+
+ public B cbi(CbComponentRefService<S> add) {
+ return cbi(add, null, null);
+ }
+
+ public B cbi(CbComponentRefService<S> add, CbComponentRefService<S> remove) {
+ return cbi(add, null, remove);
+ }
+
+ public B cbi(CbComponentRefService<S> add, CbComponentRefService<S> change, CbComponentRefService<S> remove) {
+ if (add != null)
+ setInstanceCallbackRef(Cb.ADD, (inst, comp, ref, srv) -> add.accept(comp, ref, srv));
+ if (change != null)
+ setInstanceCallbackRef(Cb.CHG, (inst, comp, ref, srv) -> change.accept(comp, ref, srv));
+ if (remove != null)
+ setInstanceCallbackRef(Cb.REM, (inst, comp, ref, srv) -> remove.accept(comp, ref, srv));
+ return (B) this;
+ }
+
+ public <T> B sw(CbTypeServiceService<T, S> swap) {
+ Class<T> type = Helpers.getLambdaArgType(swap, 0);
+ return setComponentSwapCallbackRef(type, (inst, component, oref, oserv, nref, nserv) ->
+ swap.accept((T) inst, oserv, nserv));
+ }
+
+ public <T> B sw(CbTypeComponentServiceService<T, S> swap) {
+ Class<T> type = Helpers.getLambdaArgType(swap, 0);
+ return setComponentSwapCallbackRef(type, (inst, component, oref, oserv, nref, nserv) ->
+ swap.accept((T) inst, component, oserv, nserv));
+ }
+
+ public <T> B sw(CbTypeRefServiceRefService<T, S> swap) {
+ Class<T> type = Helpers.getLambdaArgType(swap, 0);
+ return setComponentSwapCallbackRef(type, (inst, component, oref, oserv, nref, nserv) ->
+ swap.accept((T) inst, oref, oserv, nref, nserv));
+ }
+
+ public <T> B sw(CbTypeComponentRefServiceRefService<T, S> swap) {
+ Class<T> type = Helpers.getLambdaArgType(swap, 0);
+ return setComponentSwapCallbackRef(type, (inst, component, oref, oserv, nref, nserv) ->
+ swap.accept((T) inst, component, oref, oserv, nref, nserv));
+ }
+
+ public B swi(CbServiceService<S> swap) {
+ return setInstanceSwapCallbackRef((inst, component, oref, oserv, nref, nserv) -> swap.accept(oserv, nserv));
+ }
+
+ public B swi(CbComponentServiceService<S> swap) {
+ return setInstanceSwapCallbackRef((inst, component, oref, oserv, nref, nserv) -> swap.accept(component, oserv, nserv));
+ }
+
+ public B swi(CbRefServiceRefService<S> swap) {
+ return setInstanceSwapCallbackRef((inst, component, oref, oserv, nref, nserv) -> swap.accept(oref, oserv, nref, nserv));
+ }
+
+ public B swi(CbComponentRefServiceRefService<S> swap) {
+ return setInstanceSwapCallbackRef((inst, component, oref, oserv, nref, nserv) -> swap.accept(component, oref, oserv, nref, nserv));
+ }
+
+ protected <I> B setComponentCallbackRef(Cb cbType, Class<I> type, MethodRef<I, S> ref) {
+ requiresNoCallbacks();
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ List<MethodRef<Object, S>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component, sref, service) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
+ ref.accept((I) componentImpl, component, sref, service);
+ });
+ return (B) this;
+ }
+
+ protected <T> B setInstanceCallbackRef(Cb cbType, MethodRef<T, S> ref) {
+ requiresNoCallbacks();
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ List<MethodRef<Object, S>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component, sref, service) -> {
+ ref.accept((T) component.getInstance(), component, sref, service);
+ });
+ return (B) this;
+ }
+
+ public <I> B setComponentSwapCallbackRef(Class<I> type, SwapMethodRef<I, S> ref) {
+ requiresNoCallbacks();
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ m_swapRefs.add((instance, component, oref, oservice, nref, nservice) -> {
+ Object componentImpl = Stream.of(component.getInstances())
+ .filter(impl -> Helpers.getClass(impl).equals(type))
+ .findFirst()
+ .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
+ ref.accept((I) componentImpl, component, oref, oservice, nref, nservice);
+ });
+ return (B) this;
+ }
+
+ public <I> B setInstanceSwapCallbackRef(SwapMethodRef<I, S> ref) {
+ requiresNoCallbacks();
+ if (! m_autoConfigInvoked) m_autoConfig = false;
+ m_swapRefs.add((instance, component, oref, oservice, nref, nservice) -> {
+ ref.accept((I) component.getInstance(), component, oref, oservice, nref, nservice);
+ });
+ return (B) this;
+ }
+
+ Object createCallbackInstance() {
+ Object cb = null;
+
+ cb = new Object() {
+ void add(Component c, ServiceReference<S> ref, Object service) {
+ invokeMethodRefs(Cb.ADD, c, ref, (S) service);
+ }
+
+ void change(Component c, ServiceReference<S> ref, Object service) {
+ invokeMethodRefs(Cb.CHG, c, ref, (S) service);
+ }
+
+ void remove(Component c, ServiceReference<S> ref, Object service) {
+ invokeMethodRefs(Cb.REM, c, ref, (S) service);
+ }
+
+ void swap(Component c, ServiceReference<S> oldRef, Object oldSrv, ServiceReference<S> newRef, Object newSrv) {
+ invokeSwapMethodRefs(c, oldRef, (S) oldSrv, newRef, (S) newSrv);
+ }
+ };
+
+ return cb;
+ }
+
+ boolean hasRefs() {
+ return m_refs.size() > 0 || m_swapRefs.size() > 0;
+ }
+
+ boolean hasCallbacks() {
+ return m_callbackInstance != null || m_added != null || m_changed != null || m_removed != null || m_swapped != null;
+ }
+
+ String getAutoConfigField() {
+ return m_autoConfigField;
+ }
+
+ Object getCallbackInstance() {
+ return m_callbackInstance;
+ }
+
+ String getAdded() {
+ return m_added;
+ }
+
+ String getChanged() {
+ return m_changed;
+ }
+
+ String getRemoved() {
+ return m_removed;
+ }
+
+ String getSwapped() {
+ return m_swapped;
+ }
+
+ private void invokeMethodRefs(Cb cbType, Component comp, ServiceReference<S> ref, S service) {
+ m_refs.computeIfPresent(cbType, (k, mrefs) -> {
+ mrefs.forEach(mref -> mref.accept(null, comp, ref, service));
+ return mrefs;
+ });
+ }
+
+ private void invokeSwapMethodRefs(Component c, ServiceReference<S> oref, S osrv, ServiceReference<S> nref, S nsrv) {
+ m_swapRefs.forEach(ref -> ref.accept(null, c, oref, osrv, nref, nsrv));
+ }
+
+ private void requiresNoCallbacks() {
+ if (hasCallbacks()) {
+ throw new IllegalStateException("can't mix method references and string callbacks.");
+ }
+ }
+
+ private void requiresNoMethodRefs() {
+ if (hasRefs()) {
+ throw new IllegalStateException("can't mix method references and string callbacks.");
+ }
+ }
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceDependencyBuilderImpl.java b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceDependencyBuilderImpl.java
new file mode 100644
index 0000000..6892b1b
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceDependencyBuilderImpl.java
@@ -0,0 +1,148 @@
+package org.apache.felix.dm.lambda.impl;
+
+import java.util.Dictionary;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ServiceDependency;
+import org.apache.felix.dm.lambda.ServiceDependencyBuilder;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceDependencyBuilderImpl<S> extends ServiceCallbacksBuilderImpl<S, ServiceDependencyBuilder<S>> implements ServiceDependencyBuilder<S> {
+ private final Class<S> m_serviceIface;
+ private final Component m_component;
+ private String m_filter;
+ private ServiceReference<S> m_ref;
+ private boolean m_required = true;
+ private String m_debug;
+ private boolean m_propagate;
+ private Object m_propagateInstance;
+ private String m_propagateMethod;
+ private Object m_defaultImpl;
+ private long m_timeout = -1;
+
+ public ServiceDependencyBuilderImpl(Component component, Class<S> service) {
+ super(service);
+ m_serviceIface = service;
+ m_component = component;
+ }
+
+ public ServiceDependencyBuilder<S> filter(String filter) {
+ m_filter = filter;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> ref(ServiceReference<S> ref) {
+ m_ref = ref;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> optional() {
+ return required(false);
+ }
+
+ public ServiceDependencyBuilder<S> required() {
+ return required(true);
+ }
+
+ public ServiceDependencyBuilder<S> required(boolean required) {
+ m_required = required;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> debug(String label) {
+ m_debug = label;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> propagate() {
+ return propagate(true);
+ }
+
+ public ServiceDependencyBuilder<S> propagate(boolean propagate) {
+ m_propagate = propagate;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> propagate(Object instance, String method) {
+ m_propagateInstance = instance;
+ m_propagateMethod = method;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> propagate(Function<ServiceReference<S>, Dictionary<String, Object>> propagate) {
+ Object wrappedCallback = new Object() {
+ @SuppressWarnings("unused")
+ Dictionary<String, Object> propagate(ServiceReference<S> ref) {
+ return propagate.apply(ref);
+ }
+ };
+ propagate(wrappedCallback, "propagate");
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> propagate(BiFunction<ServiceReference<S>, S, Dictionary<String, Object>> propagate) {
+ Object wrappedCallback = new Object() {
+ @SuppressWarnings("unused")
+ Dictionary<String, Object> propagate(ServiceReference<S> ref, S service) {
+ return propagate.apply(ref, service);
+ }
+ };
+ propagate(wrappedCallback, "propagate");
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> defImpl(Object defaultImpl) {
+ m_defaultImpl = defaultImpl;
+ return this;
+ }
+
+ public ServiceDependencyBuilder<S> timeout(long timeout) {
+ m_timeout = timeout;
+ return this;
+ }
+
+ // Build final ServiceDependency object.
+ @Override
+ public ServiceDependency build() {
+ DependencyManager dm = m_component.getDependencyManager();
+ if (m_ref != null && m_filter != null) {
+ throw new IllegalArgumentException("Can not set ref and filter at the same time");
+ }
+ ServiceDependency sd = m_timeout > -1 ? dm.createTemporalServiceDependency(m_timeout) : dm.createServiceDependency();
+ if (m_ref != null) {
+ sd.setService(m_serviceIface, m_ref);
+ } else {
+ sd.setService(m_serviceIface, m_filter);
+ }
+ sd.setRequired(m_required);
+ sd.setDefaultImplementation(m_defaultImpl);
+ if (m_debug != null) {
+ sd.setDebug(m_debug);
+ }
+ if (m_propagate) {
+ sd.setPropagate(true);
+ } else if (m_propagateInstance != null) {
+ if (m_propagateMethod == null) {
+ throw new IllegalArgumentException("propagate instance can't be null");
+ }
+ sd.setPropagate(m_propagateInstance, m_propagateMethod);
+ }
+ if (hasCallbacks()) {
+ sd.setCallbacks(m_callbackInstance, m_added, m_changed, m_removed, m_swapped);
+ } else if (hasRefs()) {
+ Object cb = createCallbackInstance();
+ sd.setCallbacks(cb, "add", "change", "remove", m_swapRefs.size() > 0 ? "swap" : null);
+ }
+
+ if (m_autoConfigField != null) {
+ sd.setAutoConfig(m_autoConfigField);
+ } else {
+ sd.setAutoConfig(m_autoConfig);
+ }
+ return sd;
+ }
+
+}
diff --git a/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/packageinfo b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/packageinfo
new file mode 100644
index 0000000..e252556
--- /dev/null
+++ b/dependencymanager/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/packageinfo
@@ -0,0 +1 @@
+version 1.0.0
\ No newline at end of file