blob: 66631cfcae531f43fe718ecc33a66b9c72e77a06 [file] [log] [blame]
Pierre De Ropfaca2892016-01-31 23:27:05 +00001package org.apache.felix.dm.lambda.impl;
2
3import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.DESTROY;
4import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.INIT;
5import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.START;
6import static org.apache.felix.dm.lambda.impl.ComponentBuilderImpl.ComponentCallback.STOP;
7
8import java.util.ArrayList;
9import java.util.Dictionary;
10import java.util.HashMap;
11import java.util.Hashtable;
12import java.util.List;
13import java.util.Map;
14import java.util.Objects;
15import java.util.Properties;
16import java.util.concurrent.CompletableFuture;
17import java.util.function.Consumer;
18import java.util.function.Function;
19import java.util.function.Supplier;
20import java.util.stream.Stream;
21
22import org.apache.felix.dm.Component;
23import org.apache.felix.dm.Dependency;
24import org.apache.felix.dm.DependencyManager;
25import org.apache.felix.dm.lambda.BundleDependencyBuilder;
26import org.apache.felix.dm.lambda.ComponentBuilder;
27import org.apache.felix.dm.lambda.ConfigurationDependencyBuilder;
28import org.apache.felix.dm.lambda.DependencyBuilder;
Pierre De Rop0aac1362016-02-02 19:46:08 +000029import org.apache.felix.dm.lambda.FluentProperty;
Pierre De Ropfaca2892016-01-31 23:27:05 +000030import org.apache.felix.dm.lambda.FutureDependencyBuilder;
31import org.apache.felix.dm.lambda.ServiceDependencyBuilder;
Pierre De Rop11527502016-02-18 21:07:16 +000032import org.apache.felix.dm.lambda.callbacks.Cb;
Pierre De Ropfaca2892016-01-31 23:27:05 +000033import org.apache.felix.dm.lambda.callbacks.CbComponent;
Pierre De Rop11527502016-02-18 21:07:16 +000034import org.apache.felix.dm.lambda.callbacks.InstanceCb;
35import org.apache.felix.dm.lambda.callbacks.InstanceCbComponent;
Pierre De Ropfaca2892016-01-31 23:27:05 +000036
37public class ComponentBuilderImpl implements ComponentBuilder<ComponentBuilderImpl> {
38 private final List<DependencyBuilder<?>> m_dependencyBuilders = new ArrayList<>();
39 private final Component m_component;
40 private final boolean m_componentUpdated;
41 private String[] m_serviceNames;
42 private Dictionary<Object, Object> m_properties;
43 private Object m_impl;
44 private Object m_factory;
45 private boolean m_factoryHasComposite;
46 private boolean m_autoAdd = true;
47 protected final Map<ComponentCallback, List<MethodRef<Object>>> m_refs = new HashMap<>();
48 private Object m_compositionInstance;
49 private String m_compositionMethod;
50 private String m_init;
51 private String m_stop;
52 private String m_start;
53 private String m_destroy;
54 private Object m_callbackInstance;
55 private String m_factoryCreateMethod;
56 private boolean m_hasFactoryRef;
57 private boolean m_hasFactory;
58
59 enum ComponentCallback { INIT, START, STOP, DESTROY };
60
61 @FunctionalInterface
62 interface MethodRef<I> {
63 public void accept(I instance, Component c);
64 }
65
66 public ComponentBuilderImpl(DependencyManager dm) {
67 m_component = dm.createComponent();
68 m_componentUpdated = false;
69 }
70
71 public ComponentBuilderImpl(Component component, boolean update) {
72 m_component = component;
73 m_componentUpdated = update;
74 }
75
76 @Override
77 public ComponentBuilderImpl autoConfig(Class<?> clazz, boolean autoConfig) {
78 m_component.setAutoConfig(clazz, autoConfig);
79 return this;
80 }
81
82 @Override
83 public ComponentBuilderImpl autoConfig(Class<?> clazz, String instanceName) {
84 m_component.setAutoConfig(clazz, instanceName);
85 return this;
86 }
87
88 @Override
89 public ComponentBuilderImpl provides(Class<?> iface) {
90 m_serviceNames = new String[] {iface.getName()};
91 return this;
92 }
93
94 @Override
95 public ComponentBuilderImpl provides(Class<?> iface, String name, Object value, Object ... rest) {
96 provides(iface);
97 properties(name, value, rest);
98 return this;
99 }
100
101 @Override
Pierre De Rop0aac1362016-02-02 19:46:08 +0000102 public ComponentBuilderImpl provides(Class<?> iface, FluentProperty ... properties) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000103 provides(iface);
104 properties(properties);
105 return this;
106 }
107
108 @Override
109 public ComponentBuilderImpl provides(Class<?> iface, Dictionary<?,?> properties) {
110 provides(iface);
111 properties(properties);
112 return this;
113 }
114
115 @Override
116 public ComponentBuilderImpl provides(Class<?>[] ifaces) {
117 m_serviceNames = Stream.of(ifaces).map(c -> c.getName()).toArray(String[]::new);
118 return this;
119 }
120
121 @Override
122 public ComponentBuilderImpl provides(Class<?>[] ifaces, String name, Object value, Object ... rest) {
123 provides(ifaces);
124 properties(name, value, rest);
125 return this;
126 }
127
128 @Override
Pierre De Rop0aac1362016-02-02 19:46:08 +0000129 public ComponentBuilderImpl provides(Class<?>[] ifaces, FluentProperty ... properties) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000130 provides(ifaces);
131 properties(properties);
132 return this;
133 }
134
135 @Override
136 public ComponentBuilderImpl provides(Class<?>[] ifaces, Dictionary<?,?> properties) {
137 provides(ifaces);
138 properties(properties);
139 return this;
140 }
141
142 @Override
143 public ComponentBuilderImpl provides(String iface) {
144 m_serviceNames = new String[] {iface};
145 return this;
146 }
147
148 @Override
149 public ComponentBuilderImpl provides(String iface, String name, Object value, Object ... rest) {
150 provides(iface);
151 properties(name, value, rest);
152 return this;
153 }
154
155 @Override
Pierre De Rop0aac1362016-02-02 19:46:08 +0000156 public ComponentBuilderImpl provides(String iface, FluentProperty ... properties) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000157 provides(iface);
158 properties(properties);
159 return this;
160 }
161
162 @Override
163 public ComponentBuilderImpl provides(String iface, Dictionary<?,?> properties) {
164 provides(iface);
165 properties(properties);
166 return this;
167 }
168
169 @Override
170 public ComponentBuilderImpl provides(String[] ifaces) {
171 m_serviceNames = ifaces;
172 return this;
173 }
174
175 @Override
176 public ComponentBuilderImpl provides(String[] ifaces, String name, Object value, Object ... rest) {
177 provides(ifaces);
178 properties(name, value, rest);
179 return this;
180 }
181
182 @Override
Pierre De Rop0aac1362016-02-02 19:46:08 +0000183 public ComponentBuilderImpl provides(String[] ifaces, FluentProperty ... properties) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000184 provides(ifaces);
185 properties(properties);
186 return this;
187 }
188
189 @Override
190 public ComponentBuilderImpl provides(String[] ifaces, Dictionary<?,?> properties) {
191 provides(ifaces);
192 properties(properties);
193 return this;
194 }
195
196 @SuppressWarnings("unchecked")
197 @Override
198 public ComponentBuilderImpl properties(Dictionary<?, ?> properties) {
199 m_properties = (Dictionary<Object, Object>) properties;
200 return this;
201 }
202
203 @Override
204 public ComponentBuilderImpl properties(String name, Object value, Object ... rest) {
205 Objects.nonNull(name);
206 Objects.nonNull(value);
207 Properties props = new Properties();
208 props.put(name, value);
209 if ((rest.length & 1) != 0) {
210 throw new IllegalArgumentException("Invalid number of specified properties (number of arguments must be even).");
211 }
212 for (int i = 0; i < rest.length - 1; i += 2) {
213 String k = rest[i].toString().trim();
214 Object v = rest[i+1];
215 props.put(k, v);
216 }
217 m_properties = props;
218 return this;
219 }
220
221 @Override
Pierre De Rop0aac1362016-02-02 19:46:08 +0000222 public ComponentBuilderImpl properties(FluentProperty ... properties) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000223 Dictionary<Object, Object> props = new Hashtable<>();
224 Stream.of(properties).forEach(property -> {
225 String name = Helpers.getLambdaParameterName(property, 0);
226 if (name.equals("arg0")) {
227 throw new IllegalArgumentException("arg0 property name not supported");
228 }
229 Object value = property.apply(name);
230 props.put(name, value);
231 });
232 m_properties = props;
233 return this;
234 }
235
236 @Override
237 public ComponentBuilderImpl debug(String label) {
238 m_component.setDebug(label);
239 return this;
240 }
241
242 @Override
243 public ComponentBuilderImpl autoAdd(boolean autoAdd) {
244 m_autoAdd = autoAdd;
245 return this;
246 }
247
248 public ComponentBuilderImpl autoAdd() {
249 m_autoAdd = true;
250 return this;
251 }
252
253 public boolean isAutoAdd() {
254 return m_autoAdd;
255 }
256
257 @Override
258 public ComponentBuilderImpl impl(Object instance) {
259 m_impl = instance;
260 return this;
261 }
262
263 @Override
264 public ComponentBuilderImpl factory(Object factory, String createMethod) {
265 m_factory = factory;
266 m_factoryCreateMethod = createMethod;
267 ensureHasNoFactoryRef();
268 m_hasFactory = true;
269 return this;
270 }
271
272 @Override
273 public ComponentBuilderImpl factory(Supplier<?> create) {
274 Objects.nonNull(create);
275 ensureHasNoFactory();
276 m_hasFactoryRef = true;
277 m_factory = new Object() {
278 @SuppressWarnings("unused")
279 public Object create() {
280 return create.get();
281 }
282 };
283 return this;
284 }
285
286 @Override
287 public <U, V> ComponentBuilderImpl factory(Supplier<U> supplier, Function<U, V> create) {
288 Objects.nonNull(supplier);
289 Objects.nonNull(create);
290 ensureHasNoFactory();
291 m_hasFactoryRef = true;
292
293 m_factory = new Object() {
294 @SuppressWarnings("unused")
295 public Object create() {
296 U factoryImpl = supplier.get();
297 return create.apply(factoryImpl);
298 }
299 };
300 return this;
301 }
302
303 @Override
304 public ComponentBuilderImpl factory(Supplier<?> create, Supplier<Object[]> getComposite) {
305 Objects.nonNull(create);
306 Objects.nonNull(getComposite);
307 ensureHasNoFactory();
308 m_hasFactoryRef = true;
309
310 m_factory = new Object() {
311 @SuppressWarnings("unused")
312 public Object create() { // Create Factory instance
313 return create.get();
314 }
315
316 @SuppressWarnings("unused")
317 public Object[] getComposite() { // Create Factory instance
318 return getComposite.get();
319 }
320 };
321 m_factoryHasComposite = true;
322 return this;
323 }
324
325 @Override
326 public <U> ComponentBuilderImpl factory(Supplier<U> factorySupplier, Function<U, ?> factoryCreate, Function<U, Object[]> factoryGetComposite) {
327 Objects.nonNull(factorySupplier);
328 Objects.nonNull(factoryCreate);
329 Objects.nonNull(factoryGetComposite);
330 ensureHasNoFactory();
331 m_hasFactoryRef = true;
332
333 m_factory = new Object() {
334 U m_factoryInstance;
335
336 @SuppressWarnings("unused")
337 public Object create() {
338 m_factoryInstance = factorySupplier.get();
339 return factoryCreate.apply(m_factoryInstance);
340 }
341
342 @SuppressWarnings("unused")
343 public Object[] getComposite() {
344 return factoryGetComposite.apply(m_factoryInstance);
345 }
346 };
347 m_factoryHasComposite = true;
348 return this;
349 }
350
351 public ComponentBuilderImpl composition(String getCompositionMethod) {
352 return composition(null, getCompositionMethod);
353 }
354
355 public ComponentBuilderImpl composition(Object instance, String getCompositionMethod) {
356 m_compositionInstance = instance;
357 m_compositionMethod = getCompositionMethod;
358 return this;
359 }
360
361 public ComponentBuilderImpl composition(Supplier<Object[]> getCompositionMethod) {
362 m_compositionInstance = new Object() {
363 @SuppressWarnings("unused")
364 public Object[] getComposition() {
365 return getCompositionMethod.get();
366 }
367 };
368 m_compositionMethod = "getComposition";
369 return this;
370 }
371
372 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000373 public ComponentBuilderImpl withSvc(Class<?> service, String filter) {
374 return withSvc(service, srv->srv.filter(filter));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000375 }
376
377 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000378 public ComponentBuilderImpl withSvc(Class<?> ... services) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000379 for (Class<?> s : services) {
380 doWithService(s);
381 }
382 return this;
383 }
384
385 private <U> void doWithService(Class<U> service) {
386 ServiceDependencyBuilder<U> dep = new ServiceDependencyBuilderImpl<>(m_component, service);
387 m_dependencyBuilders.add(dep);
388 }
389
390 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000391 public <U> ComponentBuilderImpl withSvc(Class<U> service, Consumer<ServiceDependencyBuilder<U>> consumer) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000392 ServiceDependencyBuilder<U> dep = new ServiceDependencyBuilderImpl<>(m_component, service);
393 consumer.accept(dep);
394 m_dependencyBuilders.add(dep);
395 return this;
396 }
397
398 @Override
399 public ComponentBuilderImpl withCnf(Consumer<ConfigurationDependencyBuilder> consumer) {
400 ConfigurationDependencyBuilder dep = new ConfigurationDependencyBuilderImpl(m_component);
401 consumer.accept(dep);
402 m_dependencyBuilders.add(dep);
403 return this;
404 }
405
406 @Override
407 public ComponentBuilderImpl withBundle(Consumer<BundleDependencyBuilder> consumer) {
408 BundleDependencyBuilder dep = new BundleDependencyBuilderImpl(m_component);
409 consumer.accept(dep);
410 m_dependencyBuilders.add(dep);
411 return this;
412 }
413
414 @Override
415 public <V> ComponentBuilderImpl withFuture(CompletableFuture<V> future, Consumer<FutureDependencyBuilder<V>> consumer) {
416 FutureDependencyBuilder<V> dep = new CompletableFutureDependencyImpl<>(m_component, future);
417 consumer.accept(dep);
418 m_dependencyBuilders.add(dep);
419 return this;
420 }
421
Pierre De Rop11527502016-02-18 21:07:16 +0000422 public ComponentBuilderImpl lifecycleCallbackInstance(Object callbackInstance) {
423 m_callbackInstance = callbackInstance;
424 return this;
425 }
426
Pierre De Ropfaca2892016-01-31 23:27:05 +0000427 public ComponentBuilderImpl init(String callback) {
428 ensureHasNoLifecycleMethodRefs();
429 m_init = callback;
430 return this;
431 }
432
433 public ComponentBuilderImpl start(String callback) {
434 ensureHasNoLifecycleMethodRefs();
435 m_start = callback;
436 return this;
437 }
438
439 public ComponentBuilderImpl stop(String callback) {
440 ensureHasNoLifecycleMethodRefs();
441 m_stop = callback;
442 return this;
443 }
444
445 public ComponentBuilderImpl destroy(String callback) {
446 ensureHasNoLifecycleMethodRefs();
447 m_destroy = callback;
448 return this;
449 }
450
Pierre De Ropfaca2892016-01-31 23:27:05 +0000451 @SuppressWarnings("unchecked")
452 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000453 public <T> ComponentBuilderImpl init(Cb<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000454 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000455 setComponentCallbackRef(INIT, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000456 }
457 return this;
458 }
459
460 @SuppressWarnings("unchecked")
461 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000462 public <T> ComponentBuilderImpl start(Cb<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000463 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000464 setComponentCallbackRef(START, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000465 }
466 return this;
467 }
468
469 @SuppressWarnings("unchecked")
470 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000471 public <T> ComponentBuilderImpl stop(Cb<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000472 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000473 setComponentCallbackRef(STOP, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000474 }
475 return this;
476 }
477
478 @SuppressWarnings("unchecked")
479 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000480 public <T> ComponentBuilderImpl destroy(Cb<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000481 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000482 setComponentCallbackRef(DESTROY, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000483 }
484 return this;
485 }
486
487 @SuppressWarnings("unchecked")
488 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000489 public <T> ComponentBuilderImpl init(CbComponent<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000490 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000491 setComponentCallbackRef(INIT, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst, component));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000492 }
493 return this;
494 }
495
496 @SuppressWarnings("unchecked")
497 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000498 public <T> ComponentBuilderImpl start(CbComponent<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000499 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000500 setComponentCallbackRef(START, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst, component));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000501 }
502 return this;
503 }
504
505 @SuppressWarnings("unchecked")
506 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000507 public <T> ComponentBuilderImpl stop(CbComponent<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000508 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000509 setComponentCallbackRef(STOP, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst, component));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000510 }
511 return this;
512 }
513
514 @SuppressWarnings("unchecked")
515 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000516 public <T> ComponentBuilderImpl destroy(CbComponent<T> callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000517 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000518 setComponentCallbackRef(DESTROY, Helpers.getLambdaArgType(callback, 0), (inst, component) -> callback.accept((T) inst, component));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000519 }
520 return this;
521 }
522
523 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000524 public ComponentBuilderImpl initInstance(InstanceCb callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000525 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000526 setInstanceCallbackRef(INIT, (inst, component) -> callback.cb());
Pierre De Ropfaca2892016-01-31 23:27:05 +0000527 }
528 return this;
529 }
530
531 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000532 public ComponentBuilderImpl startInstance(InstanceCb callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000533 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000534 setInstanceCallbackRef(START, (inst, component) -> callback.cb());
Pierre De Ropfaca2892016-01-31 23:27:05 +0000535 }
536 return this;
537 }
538
539 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000540 public ComponentBuilderImpl stopInstance(InstanceCb callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000541 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000542 setInstanceCallbackRef(STOP, (inst, component) -> callback.cb());
Pierre De Ropfaca2892016-01-31 23:27:05 +0000543 }
544 return this;
545 }
546
547 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000548 public ComponentBuilderImpl destroyInstance(InstanceCb callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000549 if (callback != null) {
Pierre De Rop11527502016-02-18 21:07:16 +0000550 setInstanceCallbackRef(DESTROY, (inst, component) -> callback.cb());
Pierre De Ropfaca2892016-01-31 23:27:05 +0000551 }
552 return this;
553 }
554
555 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000556 public ComponentBuilderImpl initInstance(InstanceCbComponent callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000557 if (callback != null) {
558 setInstanceCallbackRef(INIT, (inst, component) -> callback.accept(component));
559 }
560 return this;
561 }
562
563 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000564 public ComponentBuilderImpl startInstance(InstanceCbComponent callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000565 if (callback != null) {
566 setInstanceCallbackRef(START, (inst, component) -> callback.accept(component));
567 }
568 return this;
569 }
570
571 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000572 public ComponentBuilderImpl stopInstance(InstanceCbComponent callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000573 if (callback != null) {
574 setInstanceCallbackRef(STOP, (inst, component) -> callback.accept(component));
575 }
576 return this;
577 }
578
579 @Override
Pierre De Rop11527502016-02-18 21:07:16 +0000580 public ComponentBuilderImpl destroyInstance(InstanceCbComponent callback) {
Pierre De Ropfaca2892016-01-31 23:27:05 +0000581 if (callback != null) {
582 setInstanceCallbackRef(DESTROY, (inst, component) -> callback.accept(component));
583 }
584 return this;
585 }
586
587 public Component build() {
588 if (m_serviceNames != null) {
589 m_component.setInterface(m_serviceNames, m_properties);
590 }
591
592 if (m_properties != null) {
593 m_component.setServiceProperties(m_properties);
594 }
595
596 if (! m_componentUpdated) { // Don't override impl or set callbacks if component is being updated
597 if (m_impl != null) {
598 m_component.setImplementation(m_impl);
599 m_component.setComposition(m_compositionInstance, m_compositionMethod);
600 } else {
601 Objects.nonNull(m_factory);
602 if (m_hasFactoryRef) {
603 m_component.setFactory(m_factory, "create");
604 if (m_factoryHasComposite) {
605 m_component.setComposition(m_factory, "getComposite");
606 }
607 } else {
608 m_component.setFactory(m_factory, m_factoryCreateMethod);
609 }
610 }
611
612 if (m_refs.size() > 0) {
613 setLifecycleMethodRefs();
614 } else if (hasLifecleMethods()) {
615 m_component.setCallbacks(m_callbackInstance, m_init, m_start, m_stop, m_destroy);
616 }
617 }
618
619 if (m_dependencyBuilders.size() > 0) {
620 // add atomically in case we are building some component dependencies from a component init method.
621 // We first transform the list of builders into a stream of built Dependencies, then we collect the result
622 // to an array of Dependency[].
623 m_component.add(m_dependencyBuilders.stream().map(builder -> builder.build()).toArray(Dependency[]::new));
624 }
625 return m_component;
626 }
627
628 private boolean hasLifecleMethods() {
629 return m_init != null || m_start != null || m_stop != null || m_destroy != null;
630 }
631
632 private boolean hasLifecleMethodRefs() {
633 return m_refs.size() > 0;
634 }
635
636 private void ensureHasNoLifecycleMethods() {
637 if (hasLifecleMethods()) {
638 throw new IllegalStateException("Can't mix method references and name names for lifecycle callbacks");
639 }
640 }
641
642 private void ensureHasNoLifecycleMethodRefs() {
643 if (hasLifecleMethodRefs()) {
644 throw new IllegalStateException("Can't mix method references and name names for lifecycle callbacks");
645 }
646 }
647
648 protected <U> ComponentBuilderImpl setInstanceCallbackRef(ComponentCallback cbType, MethodRef<U> ref) {
649 ensureHasNoLifecycleMethods();
650 List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
651 list.add((instance, component) -> {
652 ref.accept(null, component);
653 });
654 return this;
655 }
656
657 @SuppressWarnings("unchecked")
658 private <U> ComponentBuilderImpl setComponentCallbackRef(ComponentCallback cbType, Class<U> type, MethodRef<U> callback) {
659 ensureHasNoLifecycleMethods();
660 if (type.equals(Object.class)) {
661 throw new IllegalStateException("callback does not seam to be one from the possible component implementation classes");
662 }
663 List<MethodRef<Object>> list = m_refs.computeIfAbsent(cbType, l -> new ArrayList<>());
664 list.add((instance, component) -> {
665 Object componentImpl = Stream.of(component.getInstances())
666 .filter(impl -> Helpers.getClass(impl).equals(type))
667 .findFirst()
668 .orElseThrow(() -> new IllegalStateException("The method reference " + callback + " does not match any available component impl classes."));
669 callback.accept((U) componentImpl, component);
670 });
671 return this;
672 }
673
674 @SuppressWarnings("unused")
675 private void setLifecycleMethodRefs() {
676 Object cb = new Object() {
677 void init(Component comp) {
678 invokeLfcleCallbacks(ComponentCallback.INIT, comp);
679 }
680
681 void start(Component comp) {
682 invokeLfcleCallbacks(ComponentCallback.START, comp);
683 }
684
685 void stop(Component comp) {
686 invokeLfcleCallbacks(ComponentCallback.STOP, comp);
687 }
688
689 void destroy(Component comp) {
690 invokeLfcleCallbacks(ComponentCallback.DESTROY, comp);
691 }
692 };
693 m_component.setCallbacks(cb, "init", "start", "stop", "destroy");
694 }
695
696 private void invokeLfcleCallbacks(ComponentCallback cbType, Component component) {
697 m_refs.computeIfPresent(cbType, (k, mrefs) -> {
698 mrefs.forEach(mref -> mref.accept(null, component));
699 return mrefs;
700 });
701 }
702
703 private void ensureHasNoFactoryRef() {
704 if (m_hasFactoryRef) {
705 throw new IllegalStateException("Can't mix factory method name and factory method reference");
706 }
707 }
708
709 private void ensureHasNoFactory() {
710 if (m_hasFactory) {
711 throw new IllegalStateException("Can't mix factory method name and factory method reference");
712 }
713 }
714}