You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2016/01/28 00:27:36 UTC
svn commit: r1727214 [5/6] - in
/felix/sandbox/pderop/dependencymanager-lambda:
org.apache.felix.dependencymanager.lambda.itest/src/org/apache/felix/dm/builder/lambda/itest/
org.apache.felix.dependencymanager.lambda.samples/src/org/apache/felix/depende...
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/CompletableFutureDependencyImpl.java Wed Jan 27 23:27:34 2016
@@ -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);
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ComponentBuilderImpl.java Wed Jan 27 23:27:34 2016
@@ -0,0 +1,608 @@
+package org.apache.felix.dm.lambda.impl;
+
+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.ComponentCallback;
+import org.apache.felix.dm.lambda.ConfigurationDependencyBuilder;
+import org.apache.felix.dm.lambda.DependencyBuilder;
+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;
+import org.apache.felix.dm.lambda.callbacks.FluentProperties;
+
+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;
+
+ @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 <U> ComponentBuilderImpl autoConfig(Class<U> clazz, boolean autoConfig) {
+ m_component.setAutoConfig(clazz, autoConfig);
+ return this;
+ }
+
+ @Override
+ public <U> ComponentBuilderImpl autoConfig(Class<U> 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 <U> ComponentBuilderImpl impl(U instance) {
+ m_impl = instance;
+ return this;
+ }
+
+ @Override
+ public <U> ComponentBuilderImpl impl(Class<U> implClass) {
+ m_impl = implClass;
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl factory(Object factory, String createMethod) {
+ m_factory = factory;
+ m_factoryCreateMethod = createMethod;
+ ensureHasNoFactoryRef();
+ m_hasFactory = true;
+ return this;
+ }
+
+ @Override
+ public <U> ComponentBuilderImpl factory(Supplier<U> 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 <U> ComponentBuilderImpl factory(Supplier<U> 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, V> ComponentBuilderImpl factory(Supplier<U> factorySupplier, Function<U, V> 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 cb(ComponentCallback callbackType, String callback) {
+ ensureHasNoLifecycleMethodRefs();
+ switch (callbackType) {
+ case INIT:
+ m_init = callback;
+ break;
+
+ case START:
+ m_start = callback;
+ break;
+
+ case STOP:
+ m_stop = callback;
+ break;
+
+ case DESTROY:
+ m_destroy = callback;
+ break;
+
+ default:
+ throw new IllegalArgumentException("life method may take at max four parameters (first one for \"init\" callback, second for \"start\", third for \"stop\", and fourth for \"destroy\" callback");
+ }
+ return this;
+ }
+
+ public ComponentBuilderImpl cbi(ComponentCallback callbackType, Object callbackInstance, String callback) {
+ m_callbackInstance = callbackInstance;
+ return cb(callbackType, callback);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <U> ComponentBuilderImpl cb(ComponentCallback callbackType, CbConsumer<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(callbackType, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst));
+ }
+ return this;
+ }
+
+ @Override
+ public <U> ComponentBuilderImpl cb(ComponentCallback callbackType, CbTypeComponent<U> callback) {
+ if (callback != null) {
+ setComponentCallbackRef(callbackType, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((U) inst, component));
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl cbi(ComponentCallback callbackType, Runnable callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(callbackType, (inst, component) -> callback.run());
+ }
+ return this;
+ }
+
+ @Override
+ public ComponentBuilderImpl cbi(ComponentCallback callbackType, CbComponent callback) {
+ if (callback != null) {
+ setInstanceCallbackRef(callbackType, (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();
+ List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
+ list.add((instance, component) -> {
+ Stream.of(component.getInstances()).forEach(inst -> {
+ if (Helpers.getClass(inst).equals(type)) {
+ callback.accept((U) inst, 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");
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ConfigurationDependencyBuilderImpl.java Wed Jan 27 23:27:34 2016
@@ -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) -> {
+ Stream.of(component.getInstances()).forEach(inst -> {
+ if (Helpers.getClass(inst).equals(type)) {
+ ref.accept((T) inst, 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");
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/FactoryPidAdapterBuilderImpl.java Wed Jan 27 23:27:34 2016
@@ -0,0 +1,172 @@
+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;
+ }
+
+ @Override
+ public FactoryPidAdapterBuilderImpl autoAdd() {
+ m_autoAdd = true;
+ 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) -> {
+ Stream.of(component.getInstances()).forEach(inst -> {
+ if (Helpers.getClass(inst).equals(type)) {
+ ref.accept((U) inst, 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");
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/Helpers.java Wed Jan 27 23:27:34 2016
@@ -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"));
+ }
+
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsDictionary.java Wed Jan 27 23:27:34 2016
@@ -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(", ");
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/SRefAsMap.java Wed Jan 27 23:27:34 2016
@@ -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);
+ }
+ }
+}
Added: felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAdapterBuilderImpl.java Wed Jan 27 23:27:34 2016
@@ -0,0 +1,84 @@
+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, ServiceAdapterBuilderImpl<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> type) {
+ super(type);
+ m_dm = dm;
+ m_adapteeType = type;
+ }
+
+ @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 = m_added, change = m_changed, remove = m_removed, swap = m_swapped;
+ Object cbInstance = m_callbackInstance;
+
+ 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, m_autoConfigField, 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-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java?rev=1727214&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-lambda/org.apache.felix.dependencymanager.lambda/src/org/apache/felix/dm/lambda/impl/ServiceAspectBuilderImpl.java Wed Jan 27 23:27:34 2016
@@ -0,0 +1,89 @@
+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, ServiceAspectBuilderImpl<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> type) {
+ super(type);
+ m_dm = dm;
+ m_aspectType = type;
+ }
+
+ @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;
+ }
+
+ @Override
+ public ServiceAspectBuilderImpl<T> autoAdd() {
+ m_autoAdd = true;
+ 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 (m_autoConfigField != null && (hasRefs()|| hasCallbacks())) {
+ throw new IllegalStateException("Can't mix autoConfig fields and aspect callbacks.");
+ }
+
+ Component c = null;
+ if (m_autoConfigField != null) {
+ c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking, m_autoConfigField);
+ } 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()) {
+ c = m_dm.createAspectService(m_aspectType, m_aspectFilter, m_aspectRanking, m_added, m_changed, m_removed, m_swapped);
+ } 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();
+ }
+}