Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ComponentBuilder.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ComponentBuilder.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ComponentBuilder.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ComponentBuilder.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,271 @@ +package org.apache.felix.dm.builder.java; + +import java.util.Dictionary; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.felix.dm.Component; + +/** + * Builds a DependencyManager Component using java8 constructs. This interface provides builder methods used to configure general Component + * parameters, like:<p> + * + * <ul> + * <li> factory parameters + * <li> component service properties + * <li> component lifecycle callbacks(init/start/stop/destroy) + * <li> service dependencies + * <li> configuration dependencies + * <li> auto-injected OSGi and DM objects (BundleContext, Component, etc ...) + * </ul> + * + * Code example: + * + * <pre> {@code + * public class Activator extends DependencyActivatorBase { + * public void init() throws Exception { + * component(comp -> comp + * .provides(Service.class) + * .factory(ServiceImplFactory::new, ServiceImplFactory::create) + * .withService(LogService.class, srv -> srv.required().onAdd(ServiceImpl::set)) + * .onStart(ServiceImpl::activate)); + * } + * } + * }</pre> + * + * @param <B> This generic parameter is used by interfaces that may extends this builder, like adapters or aspect builders. + * The intent of this parameter is to be able to make each component builder method return the type of sub-interfaces. + * + * TODO: add support for reflection for lifecycle callbacks (like in Dependency Manager). + */ +public interface ComponentBuilder<B extends ComponentBuilder<B>> { + /** + * Configures the services registered by this component in the OSGgi registry + * @param ifaces the OSGi service(s) components. + * @return this builder + */ + B provides(Class<?> ... ifaces); + + /** + * Configures the component implementation. Can be a classname, or a component implementation object. + * @param impl the component implementation (a class, or an Object). + * @return this builder + */ + B impl(Object impl); + + /** + * Configures a factory that can be used to create this component implemention. + * Example: "factory(ComponentImpl::new)", or "factory(() -> new ComponentImpl())". + * + * @param create the factory used to create the component implemenation. + * @return this builder + */ + <T> B factory(Supplier<T> create); + + /** + * Configures a factory used to create this component implementation using a Factory object and a method in the Factory object. + * Example: + * + * factory(Factory::new, Factory::create) + * + * @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 + */ + <T> B factory(Supplier<T> factory, Function<T, Object> 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: + * + * CompositionManager mngr = new CompositionManager(); + * ... + * factory(mngr::create, mngr::getComposition) + * + * @param factory + * @param getComposition + * @return this builder + */ + <T> B factory(Supplier<T> factory, Supplier<Object[]> getComposition); + + /** + * Configures a factory that also returns a composition of objects for this component implemenation. + * + * Example: + * + * factory(CompositionManager::new, CompositionManager::create, CompositionManager::getComposition). + * + * 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 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 + */ + <T> B factory(Supplier<T> factory, Function<T, Object> create, Function<T, Object[]> getComposition); + + /** + * 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. + * @param properties a varargs representing a list of key-value pairs. + * + * Example: properties("param1", "value1", "service.ranking", 3) + * @return this builder + */ + B properties(Object ... properties); + + /** + * Adds a required/autoconfig service dependency. + * @param service the dependency that is required and that will be injected in any field with the same dependency type. + * @return this builder + */ + <T> B withService(Class<T> service); + + /** + * Adds a service dependency. + * @param service the service + * @param consumer the lambda for configuring the service dependency + * @return this builder. + */ + <T> B withService(Class<T> service, Consumer<ServiceDependencyBuilder<T>> consumer); + + /** + * Adds a configuration dependency. + * @param consumer the lambda used to configuration the configuration dependency. + * @return this builder. + */ + B withConfiguration(Consumer<ConfigurationDependencyBuilder> consumer); + + /** + * Sets a reference on an instance method that is called when the component is initialized. + * + * Example: onInit(instance::init) + * + * @param callback a callback that will be called when the component is initialized + * @return this builder + */ + <T> B onInit(Consumer<T> callback); + + /** + * Sets a reference on a component implementation method that is called when the component is initialized. + * + * Example: onInit(MyComponentImpl::activate) + * + * @param callback a method reference called when the component is started + * @return this builder + */ + <T> B onInit(BiConsumer<T, Component> callback); + + /** + * Sets a reference on an instance method that is called when the component is started. + * + * Example: onStart(instance::start) + * + * @param callback a callback that will be called when the component is started + * @return this builder + */ + <T> B onStart(Consumer<T> callback); + + /** + * Sets a reference on a component implementation method that is called when the component is started. + * + * Example: onStart(MyComponentImpl::started) + * + * @param callback a method reference called when the component is started + * @return this builder + */ + <T> B onStart(BiConsumer<T, Component> callback); + + /** + * Sets a reference on an instance method that is called when the component is stopped. + * + * Example: onStop(instance::stop) + * + * @param callback a callback that will be called when the component is stopped + * @return this builder + */ + <T> B onStop(Consumer<T> callback); + + /** + * Sets a reference on a component implementation method that is called when the component is started. + * + * Example: onStart(MyComponentImpl::started) + * + * @param callback a method reference called when the component is started + * @return this builder + */ + <T> B onStop(BiConsumer<T, Component> callback); + + /** + * Sets a reference on an instance method that is called when the component is destroyed. + * + * Example: onDestroy(instance::destroy) + * + * @param callback a callback that will be called when the component is destroyed + * @return this builder + */ + <T> B onDestroy(Consumer<T> callback); + + /** + * Sets a reference on a component implementation method that is called when the component is destroyed. + * + * Example: onDestroy(MyComponentImpl::destroy) + * + * @param callback a method reference called when the component is destroyed + * @return this builder + */ + <T> B onDestroy(BiConsumer<T, Component> 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 + */ + <T> B autoInject(Class<T> 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 + */ + <T> B autoInject(Class<T> 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 + * @param autoAdd true for automatically adding this component to the DependencyManager object, false if not + * @return this builder + */ + B autoAdd(boolean autoAdd); + + /** + * Is this component automatically added to its DependencyManager object ? + * @return this builder + */ + boolean autoAdd(); + + /** + * Builds the real DependencyManager Component from this Component. + * @return the real DependencyManager Component. + */ + Component build(); +}
Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ConfigurationDependencyBuilder.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ConfigurationDependencyBuilder.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ConfigurationDependencyBuilder.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ConfigurationDependencyBuilder.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,32 @@ +package org.apache.felix.dm.builder.java; + +import java.util.Dictionary; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import org.apache.felix.dm.ConfigurationDependency; + +/** + * Defines a builder for DependencyManager Configuration Dependency. + * + * Code example with a component that defines a Configuration Dependency: + * + * <pre> {@code + * public class Activator extends DependencyActivatorBase { + * public void init() throws Exception { + * component(comp -> comp + * .impl(ServiceConsumer.class) + * .withConfiguration(conf -> conf.pid(ServiceConsumer.class).onUpdate(ServiceConsumer::updated))); + * } + * }</pre> + * + * TODO: javadoc + */ +public interface ConfigurationDependencyBuilder extends DependencyBuilder<ConfigurationDependency> { + ConfigurationDependencyBuilder pid(String pid); + ConfigurationDependencyBuilder pid(Class<?> pidClass); + ConfigurationDependencyBuilder propagate(); + ConfigurationDependencyBuilder propagate(boolean propagate); + <T> ConfigurationDependencyBuilder onUpdate(BiConsumer<T, Dictionary<String, Object>> updated); + ConfigurationDependencyBuilder onUpdate(Consumer<Dictionary<String, Object>> updated); +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyActivatorBase.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyActivatorBase.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyActivatorBase.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyActivatorBase.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,199 @@ +package org.apache.felix.dm.builder.java; + +import java.util.function.Consumer; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.DependencyManager; +import org.apache.felix.dm.builder.java.impl.AdapterBuilderImpl; +import org.apache.felix.dm.builder.java.impl.AspectBuilderImpl; +import org.apache.felix.dm.builder.java.impl.ComponentBuilderImpl; +import org.apache.felix.dm.builder.java.impl.FactoryPidAdapterBuilderImpl; +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. + * Code example: + * + * <pre> {@code + * public class Activator extends DependencyActivatorBase { + * public void init() throws Exception { + * component(comp -> comp + * .provides(Provider.class) + * .factory(ProviderFactory::new, ProviderFactory::create) + * .withService(LogService.class, srv -> srv.required().onAdd(ProviderImpl::set)) + * .onStart(ProviderImpl::start)); + * } + * } + * }</pre> + * + */ +public abstract class DependencyActivatorBase implements BundleActivator { + /** + * DependencyManager object used to create/register real DM Components that are built by this activator. + */ + protected DependencyManager m_manager; + + /** + * Our Activator is starting. + */ + @Override + public void start(BundleContext context) throws Exception { + m_manager = new DependencyManager(context); + init(); + } + + /** + * Our Activator is stopped. + */ + @Override + public void stop(BundleContext context) throws Exception { + destroy(); + } + + /** + * Sub classes must override this method in order to build some DM components. + * @throws Exception + */ + protected abstract void init() throws Exception; + + /** + * Sub classes may override this method that is called when the Activator is stopped. + * @param manager + * @throws Exception + */ + protected void destroy() throws Exception { + } + + /** + * Returns the DependencyManager used to create/managed DM Components + * @return the DependencyManager associated to this Activator + */ + protected DependencyManager getDependencyManager() { + return m_manager; + } + + /** + * 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<? extends ComponentBuilder<?>>> consumer) { + return component(m_manager, consumer); + } + + /** + * Builds a DM Aspect Component using a Java8 style AspectBuilder. + * @param consumer the lambda that will use the AspectBuilder for building the DM aspect component. + * The component is auto-added to the DependencyManager, unless the lambda calls the AspectBuilder.autoAdd(false) method. + * @return a newly built DM component. + */ + protected <T> Component aspect(Class<T> aspect, Consumer<AspectBuilder<T>> consumer) { + return aspect(m_manager, aspect, consumer); + } + + /** + * Builds a DM Adapter Component using a Java8 style AdapterBuilder. + * @param consumer the lambda that will use the AdapterBuilder for building the DM adapter component. + * The component is auto-added to the DependencyManager, unless the lambda calls the AdapterBuilder.autoAdd(false) method. + * @return a newly built DM component. + */ + protected <T> Component adapter(Class<T> adaptee, Consumer<AdapterBuilder<T>> consumer) { + return adapter(m_manager, adaptee, consumer); + } + + /** + * Builds a DM Factory Configuration Adapter Component using a Java8 style FactoryPidAdapterBuilder. + * @param consumer the lambda that will use the FactoryPidAdapterBuilder for building the DM factory configuration adapter component. + * The component is auto-added to the DependencyManager, unless the lambda calls the FactoryPidAdapterBuilder.autoAdd(false) method. + * @return a newly built DM component. + */ + protected Component factoryPidAdapter(Consumer<FactoryPidAdapterBuilder> consumer) { + return factoryPidAdapter(m_manager, consumer); + } + + // These static methods can be used when building DM components outside of an activator. + + /** + * 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<? extends ComponentBuilder<?>>> consumer) { + ComponentBuilder<?> componentBuilder = new ComponentBuilderImpl(dm); + consumer.accept(componentBuilder); + Component comp = componentBuilder.build(); + if (componentBuilder.autoAdd()) { + 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 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<AspectBuilder<T>> consumer) { + AspectBuilder<T> aspectBuilder = new AspectBuilderImpl<>(dm, aspect); + consumer.accept(aspectBuilder); + Component comp = aspectBuilder.build(); + if (aspectBuilder.autoAdd()) { + dm.add(comp); + } + return comp; + } + + /** + * Builds an adapter DM Component. + * @param dm the DependencyManager object used to register the built component + * @param aspect the type of the adaptee 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<AdapterBuilder<T>> consumer) { + AdapterBuilder<T> adapterBuilder = new AdapterBuilderImpl<>(dm, adaptee); + consumer.accept(adapterBuilder); + Component comp = adapterBuilder.build(); + if (adapterBuilder.autoAdd()) { + 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) { + FactoryPidAdapterBuilder factoryPidAdapter = new FactoryPidAdapterBuilderImpl(dm); + consumer.accept(factoryPidAdapter); + Component comp = factoryPidAdapter.build(); + if (factoryPidAdapter.autoAdd()) { + dm.add(comp); + } + return comp; + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyBuilder.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyBuilder.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyBuilder.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/DependencyBuilder.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,15 @@ +package org.apache.felix.dm.builder.java; + +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 DependencyManager dependency + */ + T build(); +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/FactoryPidAdapterBuilder.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/FactoryPidAdapterBuilder.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/FactoryPidAdapterBuilder.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/FactoryPidAdapterBuilder.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,29 @@ +package org.apache.felix.dm.builder.java; + +import java.util.Dictionary; +import java.util.function.BiConsumer; + +/** + * Defines the interface for a Dependency Manager Factory Configuration Adapter. + * + * Example that defines a factory configuration adapter service for the "foo.bar" factory pid. + * + * <pre> {@code + * public class Activator extends DependencyActivatorBase { + * public void init() throws Exception { + * factoryPidAdapter(comp -> comp + * .factoryPid("foo.bar").onUpdate(ServiceImpl::updated).propagate() + * .impl(DictionaryImpl.class) + * .withService(LogService.class, dep -> dep.required(false))); + * } + * }</pre> + * + * TODO: javadoc + */ +public interface FactoryPidAdapterBuilder extends ComponentBuilder<FactoryPidAdapterBuilder> { + FactoryPidAdapterBuilder factoryPid(String pid); + FactoryPidAdapterBuilder factoryPid(Class<?> pidClass); + FactoryPidAdapterBuilder propagate(); + FactoryPidAdapterBuilder propagate(boolean propagate); + <T> FactoryPidAdapterBuilder onUpdate(BiConsumer<T, Dictionary<String, Object>> callback); +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceCallbacksBuilder.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceCallbacksBuilder.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceCallbacksBuilder.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceCallbacksBuilder.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,68 @@ +package org.apache.felix.dm.builder.java; + +import org.apache.felix.dm.builder.java.Callbacks.DictServiceDictService; +import org.apache.felix.dm.builder.java.Callbacks.InstanceDictServiceDictService; +import org.apache.felix.dm.builder.java.Callbacks.InstanceMapServiceMapService; +import org.apache.felix.dm.builder.java.Callbacks.InstanceRef; +import org.apache.felix.dm.builder.java.Callbacks.InstanceRefServiceRefService; +import org.apache.felix.dm.builder.java.Callbacks.InstanceService; +import org.apache.felix.dm.builder.java.Callbacks.InstanceServiceDict; +import org.apache.felix.dm.builder.java.Callbacks.InstanceServiceMap; +import org.apache.felix.dm.builder.java.Callbacks.InstanceServiceRef; +import org.apache.felix.dm.builder.java.Callbacks.MapServiceMapService; +import org.apache.felix.dm.builder.java.Callbacks.Ref; +import org.apache.felix.dm.builder.java.Callbacks.RefServiceRefService; +import org.apache.felix.dm.builder.java.Callbacks.Service; +import org.apache.felix.dm.builder.java.Callbacks.ServiceDict; +import org.apache.felix.dm.builder.java.Callbacks.ServiceMap; +import org.apache.felix.dm.builder.java.Callbacks.ServiceRef; + +/** + * Definition of method references for general service dependency callbacks. + * + * @param <T> a service dependency type + * @param <B> the type of a sub interface that may extends this interface + * + * TODO: add javadocs + */ +public interface ServiceCallbacksBuilder<T, B extends ServiceCallbacksBuilder<T, B>> { + <I> B onAdd(InstanceService<I, T> add); + B onAdd(Service<T> add); + <I> B onAdd(InstanceServiceMap<I, T> add); + B onAdd(ServiceMap<T> add); + <I> B onAdd(InstanceServiceDict<I, T> add); + B onAdd(ServiceDict<T> add); + <I> B onAdd(InstanceRef<I, T> add); + B onAdd(Ref<T> add); + <I> B onAdd(InstanceServiceRef<I, T> add); + B onAdd(ServiceRef<T> add); + + <I> B onChange(InstanceService<I, T> change); + B onChange(Service<T> change); + <I> B onChange(InstanceServiceMap<I, T> change); + B onChange(ServiceMap<T> change); + <I> B onChange(InstanceServiceDict<I, T> change); + B onChange(ServiceDict<T> change); + <I> B onChange(InstanceRef<I, T> change); + B onChange(Ref<T> change); + <I> B onChange(InstanceServiceRef<I, T> add); + B onChange(ServiceRef<T> add); + + <I> B onRemove(InstanceService<I, T> remove); + B onRemove(Service<T> remove); + <I> B onRemove(InstanceServiceMap<I, T> remove); + B onRemove(ServiceMap<T> remove); + <I> B onRemove(InstanceServiceDict<I, T> remove); + B onRemove(ServiceDict<T> remove); + <I> B onRemove(InstanceRef<I, T> remove); + B onRemove(Ref<T> remove); + <I> B onRemove(InstanceServiceRef<I, T> add); + B onRemove(ServiceRef<T> add); + + <I> B onSwap(InstanceRefServiceRefService<I, T> swap); + B onSwap(RefServiceRefService<T> swap); + <I> B onSwap(InstanceMapServiceMapService<I, T> swap); + B onSwap(MapServiceMapService<T> swap); + <I> B onSwap(InstanceDictServiceDictService<I, T> swap); + B onSwap(DictServiceDictService<T> swap); +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceDependencyBuilder.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceDependencyBuilder.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceDependencyBuilder.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/ServiceDependencyBuilder.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,128 @@ +package org.apache.felix.dm.builder.java; + +import org.apache.felix.dm.ServiceDependency; +import org.osgi.framework.ServiceReference; + +/** + * Defines a Service dependency. Dependency callbacks can be defined using method like (like in DependencyManager), or using method references. + * + * @param <T> the type of the service dependency + */ +public interface ServiceDependencyBuilder<T> extends DependencyBuilder<ServiceDependency>, ServiceCallbacksBuilder<T, ServiceDependencyBuilder<T>> { + /** + * Injects this dependency in all fields matching the dependency type. + * @return this builder + */ + ServiceDependencyBuilder<T> 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<T> 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<T> autoConfig(String field); + + /** + * Configures the service dependency filter + * @param filter the service filter + * @return this builder + */ + ServiceDependencyBuilder<T> filter(String filter); + + /** + * Configures this dependency with the given ServiceReference. + * @param ref the service reference + * @return this builder + */ + ServiceDependencyBuilder<T> ref(ServiceReference<T> ref); + + /** + * Configures this dependency as required. By default, a dependency is required. + * @return this builder + */ + ServiceDependencyBuilder<T> required(); + + /** + * Configures whether this dependency is required or not. + * @return this builder + */ + ServiceDependencyBuilder<T> required(boolean required); + + /** + * Configures the dependency callback instance. + * @param instance the dependency callback instance + * @return this builder + */ + ServiceDependencyBuilder<T> callbackInstance(Object instance); + + /** + * Configures the callback to invoke when the dependency becomes available + * @param added the method name to call when the dependency is available + * @return this builder + */ + ServiceDependencyBuilder<T> onAdd(String added); + + /** + * Configures the callback to invoke when the dependency is changed. + * @param changed the method name to call when the dependency is changed + * @return this builder + */ + ServiceDependencyBuilder<T> onChange(String changed); + + /** + * Configures the callback to invoke when the dependency is removed. + * @param changed the method name to call when the dependency is lost + * @return this builder + */ + ServiceDependencyBuilder<T> onRemove(String removed); + + /** + * Configures the callback to call when the service is swapped by another one + * @param swapped the method name to call on swap service event + * @return this builder + */ + ServiceDependencyBuilder<T> onSwap(String swapped); + + /** + * Configures debug mode + * @param label the label used by debug messages + * @return this builder + */ + ServiceDependencyBuilder<T> debug(String label); + + /** + * Propagates the dependency properties to the component service properties. + * @return this builder + */ + ServiceDependencyBuilder<T> propagate(); + + /** + * Configures whether the dependency properties must be propagated or not to the component service properties. + * @return this builder + */ + ServiceDependencyBuilder<T> propagate(boolean propagate); + + /** + * Configures a method that can is called in order to get propagated service properties. + * TODO: add support for method reference + * + * @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<T> propagateTo(Object instance, String method); + + /** + * 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<T> defImpl(Object defaultImpl); +} \ No newline at end of file Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AdapterBuilderImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AdapterBuilderImpl.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AdapterBuilderImpl.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AdapterBuilderImpl.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,76 @@ +package org.apache.felix.dm.builder.java.impl; + +import java.util.Objects; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.DependencyManager; +import org.apache.felix.dm.builder.java.AdapterBuilder; + +public class AdapterBuilderImpl<T> extends ExtendedComponentBase<T, AdapterBuilderImpl<T>> implements AdapterBuilder<T> { + + private final Class<?> m_adapteeType; + private String m_adapteeFilter; + private boolean m_propagate; + private String m_injectField; + private final DependencyManager m_dm; + private boolean m_autoAdd = true; + + public <U> AdapterBuilderImpl(DependencyManager dm, Class<U> type) { + m_dm = dm; + m_adapteeType = type; + } + + @Override + public AdapterBuilderImpl<T> autoAdd(boolean autoAdd) { + m_autoAdd = autoAdd; + return this; + } + + public boolean autoAdd() { + return m_autoAdd; + } + + @Override + public AdapterBuilder<T> filter(String adapteeFilter) { + m_adapteeFilter = adapteeFilter; + return this; + } + + @Override + public AdapterBuilder<T> propagate() { + m_propagate = true; + return this; + } + + @Override + public AdapterBuilder<T> propagate(boolean propagate) { + m_propagate = propagate; + return this; + } + + @Override + public AdapterBuilder<T> inject(String field) { + m_injectField = field; + return this; + } + + @Override + public Component build() { + Objects.nonNull(m_adapteeFilter); + + String add = null, change = null, remove = null, swap = null; + Object cbInstance = hasCallbacks() ? createCallbackInstance() : null; + if (cbInstance != null) { + add = "add"; + change = "change"; + remove = "remove"; + swap = "swap"; + } + Component c = m_dm.createAdapterService(m_adapteeType, m_adapteeFilter, m_injectField, 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(); + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AspectBuilderImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AspectBuilderImpl.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AspectBuilderImpl.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/AspectBuilderImpl.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,60 @@ +package org.apache.felix.dm.builder.java.impl; + +import java.util.Objects; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.DependencyManager; +import org.apache.felix.dm.builder.java.AspectBuilder; + +public class AspectBuilderImpl<T> extends ExtendedComponentBase<T, AspectBuilderImpl<T>> implements AspectBuilder<T> { + private final DependencyManager m_dm; + private final Class<?> m_aspectType; + private String m_aspectFilter; + private int m_aspectRanking; + private boolean m_autoAdd = true; + + public <U> AspectBuilderImpl(DependencyManager dm, Class<U> type) { + m_dm = dm; + m_aspectType = type; + } + + @Override + public AspectBuilderImpl<T> autoAdd(boolean autoAdd) { + m_autoAdd = autoAdd; + return this; + } + + public boolean autoAdd() { + return m_autoAdd; + } + + @Override + public AspectBuilder<T> filter(String aspectFilter) { + m_aspectFilter = aspectFilter; + return this; + } + + @Override + public AspectBuilder<T> rank(int ranking) { + m_aspectRanking = ranking; + return this; + } + + @Override + public Component build() { + Objects.nonNull(m_aspectType); + Object cbInstance = hasCallbacks() ? createCallbackInstance() : null; + String add = null, change = null, remove = null, swap = null; + if (cbInstance != null) { + add = "add"; + change = "change"; + remove = "remove"; + swap = "swap"; + } + Component c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking, add, change, remove, swap); + 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(); + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ComponentBuilderImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ComponentBuilderImpl.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ComponentBuilderImpl.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ComponentBuilderImpl.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,319 @@ +package org.apache.felix.dm.builder.java.impl; + +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.List; +import java.util.Objects; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; +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.builder.java.ComponentBuilder; +import org.apache.felix.dm.builder.java.ConfigurationDependencyBuilder; +import org.apache.felix.dm.builder.java.DependencyBuilder; +import org.apache.felix.dm.builder.java.ServiceDependencyBuilder; + +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; + + /** + * Map used to invoke actual lifecycle component method references. + * Key = "init" or "start" or "stop" or "destroy". + * Value = list of Consumers for <component.getInstance(), and the Component object itself>. + */ + private final ConcurrentHashMap<String, List<BiConsumer<?, Component>>> m_callbackMethodRefs = new ConcurrentHashMap<>(); + + 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 <T> ComponentBuilderImpl autoInject(Class<T> clazz, boolean autoConfig) { + m_component.setAutoConfig(clazz, autoConfig); + return this; + } + + @Override + public <T> ComponentBuilderImpl autoInject(Class<T> clazz, String instanceName) { + m_component.setAutoConfig(clazz, instanceName); + return this; + } + + @Override + public ComponentBuilderImpl provides(Class<?>... ifaces) { + m_serviceNames = Stream.of(ifaces).map(c -> c.getName()).toArray(String[]::new); + return this; + } + + public ComponentBuilderImpl provides(String... ifaces) { + m_serviceNames = ifaces; + return this; + } + + @SuppressWarnings("unchecked") + @Override + public ComponentBuilderImpl properties(Dictionary<?, ?> properties) { + m_properties = (Dictionary<Object, Object>) properties; + return this; + } + + @Override + public ComponentBuilderImpl properties(Object ...properties) { + Properties props = new Properties(); + if ((properties.length & 1) != 0) { + throw new IllegalArgumentException("Invalid number of specified properties (number of arguments must be even)."); + } + for (int i = 0; i < properties.length - 1; i += 2) { + String key = properties[i].toString().trim(); + Object value = properties[i+1]; + props.put(key, 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 boolean autoAdd() { + return m_autoAdd; + } + + @Override + public <T> ComponentBuilderImpl withService(Class<T> service) { + ServiceDependencyBuilder<T> dep = new ServiceDependencyBuilderImpl<T>(m_component, service); + m_dependencyBuilders.add(dep); + return this; + } + + @Override + public <T> ComponentBuilderImpl withService(Class<T> service, Consumer<ServiceDependencyBuilder<T>> consumer) { + ServiceDependencyBuilder<T> dep = new ServiceDependencyBuilderImpl<T>(m_component, service); + consumer.accept(dep); + m_dependencyBuilders.add(dep); + return this; + } + + @Override + public ComponentBuilderImpl withConfiguration(Consumer<ConfigurationDependencyBuilder> consumer) { + ConfigurationDependencyBuilder dep = new ConfigurationDependencyBuilderImpl(m_component); + consumer.accept(dep); + m_dependencyBuilders.add(dep); + return this; + } + + @Override + public ComponentBuilderImpl impl(Object instance) { + m_impl = instance; + return this; + } + + @Override + public <T> ComponentBuilderImpl factory(Supplier<T> create) { + Objects.nonNull(create); + m_factory = new Object() { + @SuppressWarnings("unused") + public Object create() { + return create.get(); + } + }; + return this; + } + + @Override + public <T> ComponentBuilderImpl factory(Supplier<T> supplier, Function<T, Object> create) { + Objects.nonNull(supplier); + Objects.nonNull(create); + + m_factory = new Object() { + @SuppressWarnings("unused") + public Object create() { + T factoryImpl = supplier.get(); + return create.apply(factoryImpl); + } + }; + return this; + } + + @Override + public <T> ComponentBuilderImpl factory(Supplier<T> create, Supplier<Object[]> getComposite) { + Objects.nonNull(create); + Objects.nonNull(getComposite); + + 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 <T> ComponentBuilderImpl factory(Supplier<T> factorySupplier, Function<T, Object> factoryCreate, Function<T, Object[]> factoryGetComposite) { + Objects.nonNull(factorySupplier); + Objects.nonNull(factoryCreate); + Objects.nonNull(factoryGetComposite); + + m_factory = new Object() { + T 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; + } + + @Override + public final <T> ComponentBuilderImpl onInit(Consumer<T> callback) { + return setLifecyceMethodRef("init", (T instance, Component comp) -> callback.accept(instance)); + } + + @Override + public final <T> ComponentBuilderImpl onInit(BiConsumer<T, Component> callback) { + return setLifecyceMethodRef("init", (T instance, Component comp) -> callback.accept(instance, comp)); + } + + @Override + public final <T> ComponentBuilderImpl onStart(Consumer<T> callback) { + return setLifecyceMethodRef("start", (T instance, Component comp) -> callback.accept(instance)); + } + + @Override + public final <T> ComponentBuilderImpl onStart(BiConsumer<T, Component> callback) { + return setLifecyceMethodRef("start", (T instance, Component comp) -> callback.accept(instance, comp)); + } + + @Override + public final <T> ComponentBuilderImpl onStop(Consumer<T> callback) { + return setLifecyceMethodRef("stop", (T instance, Component comp) -> callback.accept(instance)); + } + + @Override + public final <T> ComponentBuilderImpl onStop(BiConsumer<T, Component> callback) { + return setLifecyceMethodRef("stop", (T instance, Component comp) -> callback.accept(instance, comp)); + } + + @Override + public final <T> ComponentBuilderImpl onDestroy(Consumer<T> callback) { + return setLifecyceMethodRef("destroy", (T instance, Component comp) -> callback.accept(instance)); + } + + @Override + public final <T> ComponentBuilderImpl onDestroy(BiConsumer<T, Component> callback) { + return setLifecyceMethodRef("destroy", (T instance, Component comp) -> callback.accept(instance, comp)); + } + + 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); + } else { + Objects.nonNull(m_factory); + m_component.setFactory(m_factory, "create"); + if (m_factoryHasComposite) { + m_component.setComposition(m_factory, "getComposite"); + } + } + + if (m_callbackMethodRefs.size() > 0) { + setLifecycleMethodRefs(); + } + } + + 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 <T> ComponentBuilderImpl setLifecyceMethodRef(String lifecycle, BiConsumer<T, Component> callback) { + m_callbackMethodRefs.computeIfAbsent(lifecycle, l -> new ArrayList<>()).add(callback); + return this; + } + + @SuppressWarnings("unused") + private void setLifecycleMethodRefs() { + Object cb = new Object() { + void init(Component comp) { + invokeLifecycleMethodRefs("init", comp); + } + + void start(Component comp) { + invokeLifecycleMethodRefs("start", comp); + } + + void stop(Component comp) { + invokeLifecycleMethodRefs("stop", comp); + } + + void destroy(Component comp) { + invokeLifecycleMethodRefs("destroy", comp); + } + }; + m_component.setCallbacks(cb, "init", "start", "stop", "destroy"); + } + + void invokeLifecycleMethodRefs(String lifecycle, Component component) { + m_callbackMethodRefs.computeIfPresent(lifecycle, (k, refs) -> { + refs.stream().forEach(ref -> ref.accept(component.getInstance(), component)); + return refs; + }); + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ConfigurationDependencyBuilderImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ConfigurationDependencyBuilderImpl.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ConfigurationDependencyBuilderImpl.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ConfigurationDependencyBuilderImpl.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,104 @@ +package org.apache.felix.dm.builder.java.impl; + +import java.util.Dictionary; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.ConfigurationDependency; +import org.apache.felix.dm.builder.java.ConfigurationDependencyBuilder; +import org.apache.felix.dm.context.ComponentContext; + +import net.jodah.typetools.TypeResolver; + +public class ConfigurationDependencyBuilderImpl implements ConfigurationDependencyBuilder { + private String m_pid; + private boolean m_propagate; + private Consumer<Dictionary<String, Object>> m_updatedConsumers = (props -> {}); + private boolean m_updatedConsumersSet; + private final Component m_component; + + /** + * Mapping between component instances and corresponding "updated" method references. + */ + private final ConcurrentHashMap<Class<?>, BiConsumer<?, Dictionary<String, Object>>> m_componentInstanceCallbackRefs = new ConcurrentHashMap<>(); + + 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; + } + + @Override + public <T> ConfigurationDependencyBuilder onUpdate(BiConsumer<T, Dictionary<String, Object>> updatedRef) { + Class<?> instanceType = TypeResolver.resolveRawArguments(BiConsumer.class, updatedRef.getClass())[0]; + m_componentInstanceCallbackRefs.put(instanceType, updatedRef); + return this; + } + + @Override + public ConfigurationDependencyBuilder onUpdate(Consumer<Dictionary<String, Object>> updatedConsumer) { + m_updatedConsumers = m_updatedConsumers.andThen(props -> updatedConsumer.accept(props)); + m_updatedConsumersSet = true; + return null; + } + + @Override + public ConfigurationDependency build() { + ConfigurationDependency dep = m_component.getDependencyManager().createConfigurationDependency(); + Objects.nonNull(m_pid); + dep.setPid(m_pid); + dep.setPropagate(m_propagate); + + if (m_componentInstanceCallbackRefs.size() > 0) { + // Some method refs have been added on some component instances. + dep.setCallback(new Object() { + @SuppressWarnings({ "unused", "unchecked" }) + void updated(Component comp, Dictionary<String, Object> props) { + ((ComponentContext) comp).instantiateComponent(); + Stream.of(comp.getInstances()).forEach(instance -> { + BiConsumer<Object, Dictionary<String, Object>> updatedRef = (BiConsumer<Object, Dictionary<String, Object>>) m_componentInstanceCallbackRefs.get(instance.getClass()); + if (updatedRef != null) { + updatedRef.accept(instance, props); + } + }); + m_updatedConsumers.accept(props); + } + }, "updated"); + } else if (m_updatedConsumersSet) { + // Some consumers have been configured, call them on any updated properties. + dep.setCallback(new Object() { + @SuppressWarnings("unused") + void updated(Dictionary<String, Object> props) { + m_updatedConsumers.accept(props); + } + }, "updated"); + } + return dep; + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ExtendedComponentBase.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ExtendedComponentBase.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ExtendedComponentBase.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/ExtendedComponentBase.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,144 @@ +package org.apache.felix.dm.builder.java.impl; + +import java.util.Dictionary; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.builder.java.ComponentBuilder; +import org.apache.felix.dm.builder.java.ConfigurationDependencyBuilder; +import org.apache.felix.dm.builder.java.ServiceDependencyBuilder; + +/** + * Methods common to extended components like adapters or aspects. + * Two things are provided to sub classes (to adapters/aspects): + * + * 1) Dependency callback management (aspect and adapters API both contain service callbacks) + * + * 2) This class also implements the ComponentBuilder interface. The ComponentBuilder implemented methods don't do anything, we just + * keep track the list of called methods using a composition of Consumers of ComponentBuilder. This allows to easily + * cache the list of invoked ComponentBuilder methods, and then later, invoke the methods in one shot. + */ +@SuppressWarnings({"unchecked"}) +public abstract class ExtendedComponentBase<T, B extends ExtendedComponentBase<T, B>> extends ServiceCallbacksBuilderImpl<T, B> { + + /** + * List of invoked ComponentBuilder methods. + */ + protected Consumer<ComponentBuilder<? extends ComponentBuilder<?>>> m_compBuilder = (componentBuilder -> {}); + + // ComponentBuilder methods: we are using Consumer.andThen that allows to maintain the chain of called methods (function composition). + + public B impl(Object impl) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.impl(impl)); + return (B) this; + } + + public <U> B factory(Supplier<U> create) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.factory(create)); + return (B) this; + } + + public <U> B factory(Supplier<U> factory, Function<U, Object> create) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.factory(factory, create)); + return (B) this; + } + + public <U> B factory(Supplier<U> factory, Supplier<Object[]> getComposition) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.factory(factory, getComposition)); + return (B) this; + } + + public <U> B factory(Supplier<U> factory, Function<U, Object> create, Function<U, Object[]> getComposition) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.factory(factory, create, getComposition)); + return (B) this; + } + + public B provides(Class<?> ... ifaces) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.provides(ifaces)); + return (B) this; + } + + public B properties(Dictionary<?, ?> properties) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.properties(properties)); + return (B) this; + } + + public B properties(Object ... properties) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.properties(properties)); + return (B) this; + } + + public <U> B withService(Class<U> service) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.withService(service)); + return (B) this; + } + + public <U> B withService(Class<U> service, Consumer<ServiceDependencyBuilder<U>> consumer) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.withService(service, consumer)); + return (B) this; + } + + public B withConfiguration(Consumer<ConfigurationDependencyBuilder> consumer) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.withConfiguration(consumer)); + return (B) this; + } + + public <U> B onInit(Consumer<U> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onInit(callback)); + return (B) this; + } + + public <U> B onInit(BiConsumer<U, Component> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onInit(callback)); + return (B) this; + } + + public <U> B onStart(Consumer<U> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onStart(callback)); + return (B) this; + } + + public <U> B onStart(BiConsumer<U, Component> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onStart(callback)); + return (B) this; + } + + public <U> B onStop(Consumer<U> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onStop(callback)); + return (B) this; + } + + public <U> B onStop(BiConsumer<U, Component> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onStop(callback)); + return (B) this; + } + + public <U> B onDestroy(Consumer<U> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onDestroy(callback)); + return (B) this; + } + + public <U> B onDestroy(BiConsumer<U, Component> callback) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.onDestroy(callback)); + return (B) this; + } + + public <U> B autoInject(Class<U> clazz, boolean autoConfig) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.autoInject(clazz, autoConfig)); + return (B) this; + } + + public <U> B autoInject(Class<U> clazz, String field) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.autoInject(clazz, field)); + return (B) this; + } + + public B debug(String label) { + m_compBuilder = m_compBuilder.andThen(compBuilder -> compBuilder.debug(label)); + return (B) this; + } + +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/FactoryPidAdapterBuilderImpl.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/FactoryPidAdapterBuilderImpl.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/FactoryPidAdapterBuilderImpl.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/FactoryPidAdapterBuilderImpl.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,99 @@ +package org.apache.felix.dm.builder.java.impl; + +import java.util.Dictionary; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +import org.apache.felix.dm.Component; +import org.apache.felix.dm.DependencyManager; +import org.apache.felix.dm.builder.java.FactoryPidAdapterBuilder; + +import net.jodah.typetools.TypeResolver; + +public class FactoryPidAdapterBuilderImpl + extends ExtendedComponentBase<Object, FactoryPidAdapterBuilderImpl> + implements FactoryPidAdapterBuilder +{ + protected final ConcurrentHashMap<Class<?>, BiConsumer<?, Dictionary<String, Object>>> m_callbacks = new ConcurrentHashMap<>(); + private String m_factoryPid; + private boolean m_propagate; + private final DependencyManager m_dm; + private boolean m_autoAdd = true; + + public FactoryPidAdapterBuilderImpl(DependencyManager dm) { + m_dm = dm; + } + + @Override + public FactoryPidAdapterBuilderImpl autoAdd(boolean autoAdd) { + m_autoAdd = autoAdd; + return this; + } + + public boolean autoAdd() { + 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; + } + + @Override + public <T> FactoryPidAdapterBuilder onUpdate(BiConsumer<T, Dictionary<String, Object>> callback) { + Class<?> instanceType = TypeResolver.resolveRawArguments(BiConsumer.class, callback.getClass())[0]; + setUpdateRef(instanceType, (T instance, Dictionary<String, Object> conf) -> callback.accept(instance, conf)); + return this; + } + + @Override + public Component build() { + Objects.nonNull(m_factoryPid); + if (m_callbacks.size() == 0) { + throw new IllegalStateException("No callbacks configured in factory pid adapter"); + } + Object wrapCallback = new Object() { + @SuppressWarnings({ "unused", "unchecked" }) + public void updated(Component comp, Dictionary<String, Object> conf) { + Stream.of(comp.getInstances()).forEach(instance -> { + BiConsumer<Object, Dictionary<String, Object>> updateCB = + (BiConsumer<Object, Dictionary<String, Object>>) m_callbacks.get(instance.getClass()); + if (updateCB != null) { + updateCB.accept(instance, conf); + } + }); + + } + }; + Component c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, "updated", m_propagate, wrapCallback); + ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false); + m_compBuilder.accept (cb); + return cb.build(); + } + + public <T> FactoryPidAdapterBuilder setUpdateRef(Class<?> instanceType, BiConsumer<T, Dictionary<String, Object>> updateCB) { + m_callbacks.put(instanceType, updateCB); + return this; + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsDictionary.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsDictionary.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsDictionary.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsDictionary.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,94 @@ +package org.apache.felix.dm.builder.java.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(", "); + } + } +} Added: felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsMap.java URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsMap.java?rev=1714132&view=auto ============================================================================== --- felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsMap.java (added) +++ felix/sandbox/pderop/dependencymanager.builder.java/org.apache.felix.dependencymanager.builder.java/src/org/apache/felix/dm/builder/java/impl/SRefAsMap.java Thu Nov 12 22:26:29 2015 @@ -0,0 +1,84 @@ +package org.apache.felix.dm.builder.java.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); + } + } +}
