blob: 9f8a2e893bff79fef1e40704c540dbc3b2b0de8f [file] [log] [blame]
Pierre De Rop11527502016-02-18 21:07:16 +00001package org.apache.felix.dm.lambda.callbacks;
2
3import java.util.Collection;
4import java.util.Dictionary;
5import java.util.Map;
6import java.util.Objects;
7
8/**
9 * Represents a callback(Configuration) that is invoked on a Component implementation class.
10 * The callback which accepts a type-safe configuration class for wrapping properties behind a dynamic proxy interface.
11 *
12 * <p> The T generic parameter represents the type of the class on which the callback is invoked on.
13 * <p> The U generic parameter represents the type of the configuration class passed to the callback argument.
14 *
15 * <p> Using such callback provides a way for creating type-safe configurations from a actual {@link Map} or {@link Dictionary} that is
16 * normally injected by Dependency Manager.
17 * The callback accepts in argument an interface that you have to provide, and DM will inject a proxy that converts
18 * method calls from your configuration-type to lookups in the actual map or dictionary. The results of these lookups are then
19 * converted to the expected return type of the invoked configuration method.<br>
20 * As proxies are injected, no implementations of the desired configuration-type are necessary!
21 * </p>
22 * <p>
23 * The lookups performed are based on the name of the method called on the configuration type. The method names are
24 * "mangled" to the following form: <tt>[lower case letter] [any valid character]*</tt>. Method names starting with
25 * <tt>get</tt> or <tt>is</tt> (JavaBean convention) are stripped from these prefixes. For example: given a dictionary
26 * with the key <tt>"foo"</tt> can be accessed from a configuration-type using the following method names:
27 * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.
28 * </p>
29 * <p>
30 * The return values supported are: primitive types (or their object wrappers), strings, enums, arrays of
31 * primitives/strings, {@link Collection} types, {@link Map} types, {@link Class}es and interfaces. When an interface is
32 * returned, it is treated equally to a configuration type, that is, it is returned as a proxy.
33 * </p>
34 * <p>
35 * Arrays can be represented either as comma-separated values, optionally enclosed in square brackets. For example:
36 * <tt>[ a, b, c ]</tt> and <tt>a, b,c</tt> are both considered an array of length 3 with the values "a", "b" and "c".
37 * Alternatively, you can append the array index to the key in the dictionary to obtain the same: a dictionary with
38 * "arr.0" =&gt; "a", "arr.1" =&gt; "b", "arr.2" =&gt; "c" would result in the same array as the earlier examples.
39 * </p>
40 * <p>
41 * Maps can be represented as single string values similarly as arrays, each value consisting of both the key and value
42 * separated by a dot. Optionally, the value can be enclosed in curly brackets. Similar to array, you can use the same
43 * dot notation using the keys. For example, a dictionary with
44 *
45 * <pre>{@code "map" => "{key1.value1, key2.value2}"}</pre>
46 *
47 * and a dictionary with <p>
48 *
49 * <pre>{@code "map.key1" => "value1", "map2.key2" => "value2"}</pre>
50 *
51 * result in the same map being returned.
52 * Instead of a map, you could also define an interface with the methods <tt>getKey1()</tt> and <tt>getKey2</tt> and use
53 * that interface as return type instead of a {@link Map}.
54 *
55 * <p>
56 * In case a lookup does not yield a value from the underlying map or dictionary, the following rules are applied:
57 * <ol>
58 * <li>primitive types yield their default value, as defined by the Java Specification;
59 * <li>string, {@link Class}es and enum values yield <code>null</code>;
60 * <li>for arrays, collections and maps, an empty array/collection/map is returned;
61 * <li>for other interface types that are treated as configuration type a null-object is returned.
62 * </ol>
63 * </p>
64 *
65 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
66 */
67@FunctionalInterface
68public interface CbConfiguration<T, U> extends SerializableLambda {
69 /**
70 * Handles the given arguments
71 * @param instance the Component implementation instance on which the callback is invoked on.
72 * @param configuration the configuration proxy
73 */
74 void accept(T instance, U configuration);
75
76 default CbConfiguration<T, U> andThen(CbConfiguration<T, U> after) {
77 Objects.requireNonNull(after);
78 return (T instance, U configuration) -> {
79 accept(instance, configuration);
80 after.accept(instance, configuration);
81 };
82 }
83}