blob: 4bec1932081929b6e9814e0a94519d134f90212d [file] [log] [blame]
Pierre De Ropfaca2892016-01-31 23:27:05 +00001package org.apache.felix.dm.lambda.impl;
2
3import java.util.ArrayList;
4import java.util.Dictionary;
5import java.util.List;
6import java.util.Objects;
7import java.util.function.Consumer;
8import java.util.stream.Stream;
9
10import org.apache.felix.dm.Component;
11import org.apache.felix.dm.DependencyManager;
Pierre De Rop11527502016-02-18 21:07:16 +000012import org.apache.felix.dm.context.ComponentContext;
Pierre De Ropfaca2892016-01-31 23:27:05 +000013import org.apache.felix.dm.lambda.ComponentBuilder;
14import org.apache.felix.dm.lambda.FactoryPidAdapterBuilder;
Pierre De Rop11527502016-02-18 21:07:16 +000015import org.apache.felix.dm.lambda.callbacks.CbConfiguration;
16import org.apache.felix.dm.lambda.callbacks.CbConfigurationComponent;
Pierre De Ropfaca2892016-01-31 23:27:05 +000017import org.apache.felix.dm.lambda.callbacks.CbDictionary;
Pierre De Rop11527502016-02-18 21:07:16 +000018import org.apache.felix.dm.lambda.callbacks.CbDictionaryComponent;
19import org.apache.felix.dm.lambda.callbacks.InstanceCbConfiguration;
20import org.apache.felix.dm.lambda.callbacks.InstanceCbConfigurationComponent;
21import org.apache.felix.dm.lambda.callbacks.InstanceCbDictionary;
22import org.apache.felix.dm.lambda.callbacks.InstanceCbDictionaryComponent;
Pierre De Ropfaca2892016-01-31 23:27:05 +000023
24public class FactoryPidAdapterBuilderImpl implements AdapterBase<FactoryPidAdapterBuilder>, FactoryPidAdapterBuilder {
25 private String m_factoryPid;
26 private boolean m_propagate;
27 private final DependencyManager m_dm;
28 private boolean m_autoAdd = true;
29 private String m_updateMethodName;
30 private Object m_updateCallbackInstance;
31 private boolean m_hasMethodRefs;
32 private boolean m_hasReflectionCallback;
33 private Consumer<ComponentBuilder<?>> m_compBuilder = (componentBuilder -> {});
34 private final List<MethodRef<Object>> m_refs = new ArrayList<>();
Pierre De Rop11527502016-02-18 21:07:16 +000035 private Class<?> m_configType;
Pierre De Ropfaca2892016-01-31 23:27:05 +000036
37 @FunctionalInterface
38 interface MethodRef<I> {
39 public void accept(I instance, Component c, Dictionary<String, Object> props);
40 }
41
42 public FactoryPidAdapterBuilderImpl(DependencyManager dm) {
43 m_dm = dm;
44 }
45
46 public void andThenBuild(Consumer<ComponentBuilder<?>> builder) {
47 m_compBuilder = m_compBuilder.andThen(builder);
48 }
49
50 @Override
51 public FactoryPidAdapterBuilderImpl autoAdd(boolean autoAdd) {
52 m_autoAdd = autoAdd;
53 return this;
54 }
55
56 public boolean isAutoAdd() {
57 return m_autoAdd;
58 }
59
60 @Override
61 public FactoryPidAdapterBuilder factoryPid(String pid) {
62 m_factoryPid = pid;
63 return this;
64 }
65
66 @Override
Pierre De Ropfaca2892016-01-31 23:27:05 +000067 public FactoryPidAdapterBuilder propagate() {
68 m_propagate = true;
69 return this;
70 }
71
72 @Override
73 public FactoryPidAdapterBuilder propagate(boolean propagate) {
74 m_propagate = propagate;
75 return this;
76 }
77
Pierre De Rop11527502016-02-18 21:07:16 +000078 @Override
79 public FactoryPidAdapterBuilder update(String update) {
Pierre De Ropfaca2892016-01-31 23:27:05 +000080 checkHasNoMethodRefs();
81 m_hasReflectionCallback = true;
82 m_updateMethodName = update;
83 return this;
84 }
85
Pierre De Rop11527502016-02-18 21:07:16 +000086 @Override
87 public FactoryPidAdapterBuilder update(Class<?> configType, String updateMethod) {
88 update(updateMethod);
89 m_configType = configType;
90 return this;
91 }
92
93 @Override
94 public FactoryPidAdapterBuilder update(Object callbackInstance, String update) {
95 update(update);
Pierre De Ropfaca2892016-01-31 23:27:05 +000096 m_updateCallbackInstance = callbackInstance;
97 return this;
98 }
99
100 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000101 public FactoryPidAdapterBuilder update(Class<?> configType, Object callbackInstance, String updateMethod) {
102 update(callbackInstance, updateMethod);
103 m_configType = configType;
104 return this;
Pierre De Ropfaca2892016-01-31 23:27:05 +0000105 }
106
107 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000108 public <T> FactoryPidAdapterBuilder update(CbDictionary<T> callback) {
109 Class<T> type = Helpers.getLambdaArgType(callback, 0);
110 return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((T) instance, props); });
111 }
112
113 @Override
114 public <T, U> FactoryPidAdapterBuilder update(Class<U> configType, CbConfiguration<T, U> callback) {
115 Class<T> type = Helpers.getLambdaArgType(callback, 0);
116 m_factoryPid = m_factoryPid == null ? configType.getName() : m_factoryPid;
117 return setComponentCallbackRef(type, (instance, component, props) -> {
118 U configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props);
119 callback.accept((T) instance, configProxy);
120 });
121 }
122
123 @Override
124 public <T> FactoryPidAdapterBuilder update(CbDictionaryComponent<T> callback) {
125 Class<T> type = Helpers.getLambdaArgType(callback, 0);
126 return setComponentCallbackRef(type, (instance, component, props) -> { callback.accept((T) instance, props, component); });
Pierre De Ropfaca2892016-01-31 23:27:05 +0000127 }
128
129 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000130 public <T, U> FactoryPidAdapterBuilder update(Class<U> configType, CbConfigurationComponent<T, U> callback) {
131 Class<T> type = Helpers.getLambdaArgType(callback, 0);
132 m_factoryPid = m_factoryPid == null ? configType.getName() : m_factoryPid;
133 return setComponentCallbackRef(type, (instance, component, props) -> {
134 U configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props);
135 callback.accept((T) instance, configProxy, component);
136 });
137 }
138
139 @Override
140 public FactoryPidAdapterBuilder update(InstanceCbDictionary callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000141 return setInstanceCallbackRef((instance, component, props) -> { callback.accept(props); });
142 }
Pierre De Rop11527502016-02-18 21:07:16 +0000143
144 @Override
145 public <T> FactoryPidAdapterBuilder update(Class<T> configType, InstanceCbConfiguration<T> callback) {
146 return setInstanceCallbackRef((instance, component, props) -> {
147 T configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props);
148 callback.accept(configProxy);
149 });
150 }
Pierre De Ropfaca2892016-01-31 23:27:05 +0000151
152 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000153 public FactoryPidAdapterBuilder update(InstanceCbDictionaryComponent callback) {
154 return setInstanceCallbackRef((instance, component, props) -> { callback.accept(props, component); });
155 }
156
157 @Override
158 public <T> FactoryPidAdapterBuilder update(Class<T> configType, InstanceCbConfigurationComponent<T> callback) {
159 return setInstanceCallbackRef((instance, component, props) -> {
160 T configProxy = ((ComponentContext) component).createConfigurationProxy(configType, props);
161 callback.accept(configProxy, component);
162 });
Pierre De Ropfaca2892016-01-31 23:27:05 +0000163 }
164
165 @Override
166 public Component build() {
167 Objects.nonNull(m_factoryPid);
168 Component c = null;
169
170 if (m_hasMethodRefs) {
171 Object wrapCallback = new Object() {
172 @SuppressWarnings("unused")
173 public void updated(Component comp, Dictionary<String, Object> conf) {
174 m_refs.forEach(mref -> mref.accept(null, comp, conf));
175 }
176 };
177 c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, "updated", m_propagate, wrapCallback);
178 } else {
Pierre De Rop11527502016-02-18 21:07:16 +0000179 c = m_dm.createFactoryConfigurationAdapterService(m_factoryPid, m_updateMethodName, m_propagate, m_updateCallbackInstance, m_configType);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000180 }
181 ComponentBuilderImpl cb = new ComponentBuilderImpl(c, false);
182 m_compBuilder.accept (cb);
183 return cb.build();
184 }
185
Pierre De Rop11527502016-02-18 21:07:16 +0000186 private <T> FactoryPidAdapterBuilder setInstanceCallbackRef(MethodRef<T> ref) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000187 checkHasNoReflectionCallbacks();
188 m_hasMethodRefs = true;
189 m_refs.add((instance, component, props) -> ref.accept(null, component, props));
190 return this;
191 }
192
193 @SuppressWarnings("unchecked")
Pierre De Rop11527502016-02-18 21:07:16 +0000194 private <T> FactoryPidAdapterBuilder setComponentCallbackRef(Class<T> type, MethodRef<T> ref) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000195 checkHasNoReflectionCallbacks();
196 m_hasMethodRefs = true;
197 m_refs.add((instance, component, props) -> {
198 Object componentImpl = Stream.of(component.getInstances())
199 .filter(impl -> Helpers.getClass(impl).equals(type))
200 .findFirst()
201 .orElseThrow(() -> new IllegalStateException("The method reference " + ref + " does not match any available component impl classes."));
Pierre De Rop11527502016-02-18 21:07:16 +0000202 ref.accept((T) componentImpl, component, props);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000203 });
204 return this;
205 }
206
207 private void checkHasNoMethodRefs() {
208 if (m_hasMethodRefs) {
209 throw new IllegalStateException("Can't mix method references with reflection based callbacks");
210 }
211 }
212
213 private void checkHasNoReflectionCallbacks() {
214 if (m_hasReflectionCallback) {
215 throw new IllegalStateException("Can't mix method references with reflection based callbacks");
216 }
217 }
218}