blob: 60a3537b0004d9b3a74a41bd997b70a77c5e2ef7 [file] [log] [blame]
Pierre De Ropfaca2892016-01-31 23:27:05 +00001package org.apache.felix.dm.lambda;
2
Pierre De Rop11527502016-02-18 21:07:16 +00003import java.util.Collection;
4import java.util.Dictionary;
5import java.util.Map;
6
Pierre De Ropfaca2892016-01-31 23:27:05 +00007import org.apache.felix.dm.ConfigurationDependency;
Pierre De Rop11527502016-02-18 21:07:16 +00008import org.apache.felix.dm.lambda.callbacks.CbConfiguration;
9import org.apache.felix.dm.lambda.callbacks.CbConfigurationComponent;
Pierre De Ropfaca2892016-01-31 23:27:05 +000010import org.apache.felix.dm.lambda.callbacks.CbDictionary;
Pierre De Rop11527502016-02-18 21:07:16 +000011import org.apache.felix.dm.lambda.callbacks.CbDictionaryComponent;
12import org.apache.felix.dm.lambda.callbacks.InstanceCbConfiguration;
13import org.apache.felix.dm.lambda.callbacks.InstanceCbConfigurationComponent;
14import org.apache.felix.dm.lambda.callbacks.InstanceCbDictionary;
15import org.apache.felix.dm.lambda.callbacks.InstanceCbDictionaryComponent;
Pierre De Ropfaca2892016-01-31 23:27:05 +000016
17/**
18 * Builds a Dependency Manager Configuration Dependency.
Pierre De Rop11527502016-02-18 21:07:16 +000019 * Two families of callbacks are supported: <p>
Pierre De Ropfaca2892016-01-31 23:27:05 +000020 *
Pierre De Rop11527502016-02-18 21:07:16 +000021 * <ul>
22 * <li>reflection based callbacks: you specify a callback method name
23 * <li>method reference callbacks: you specify a java8 method reference
24 * </ul>
25 *
26 * <p> Callbacks may accept a Dictionary, a Component, or a user defined configuration type interface.
27 *
28 * If you only specify a pid, by default the callback method name is assumed to be "updated".
29 *
30 * <p> Configuration types are a new feature that allows you to specify an interface that is implemented
31 * by DM and such interface is then injected to your callback instead of the actual Dictionary.
32 * Using such configuration interface provides a way for creating type-safe configurations from a actual {@link Dictionary} that is
33 * normally injected by Dependency Manager.
34 * The callback accepts in argument an interface that you have to provide, and DM will inject a proxy that converts
35 * method calls from your configuration-type to lookups in the actual map or dictionary. The results of these lookups are then
36 * converted to the expected return type of the invoked configuration method.<br>
37 * As proxies are injected, no implementations of the desired configuration-type are necessary!
38 * </p>
39 * <p>
40 * The lookups performed are based on the name of the method called on the configuration type. The method names are
41 * "mangled" to the following form: <tt>[lower case letter] [any valid character]*</tt>. Method names starting with
42 * <tt>get</tt> or <tt>is</tt> (JavaBean convention) are stripped from these prefixes. For example: given a dictionary
43 * with the key <tt>"foo"</tt> can be accessed from a configuration-type using the following method names:
44 * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.
45 * </p>
46 * <p>
47 * The return values supported are: primitive types (or their object wrappers), strings, enums, arrays of
48 * primitives/strings, {@link Collection} types, {@link Map} types, {@link Class}es and interfaces. When an interface is
49 * returned, it is treated equally to a configuration type, that is, it is returned as a proxy.
50 * </p>
51 * <p>
52 * Arrays can be represented either as comma-separated values, optionally enclosed in square brackets. For example:
53 * <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".
54 * Alternatively, you can append the array index to the key in the dictionary to obtain the same: a dictionary with
55 * "arr.0" =&gt; "a", "arr.1" =&gt; "b", "arr.2" =&gt; "c" would result in the same array as the earlier examples.
56 * </p>
57 * <p>
58 * Maps can be represented as single string values similarly as arrays, each value consisting of both the key and value
59 * separated by a dot. Optionally, the value can be enclosed in curly brackets. Similar to array, you can use the same
60 * dot notation using the keys. For example, a dictionary with
61 *
62 * <pre>{@code "map" => "{key1.value1, key2.value2}"}</pre>
63 *
64 * and a dictionary with <p>
65 *
66 * <pre>{@code "map.key1" => "value1", "map2.key2" => "value2"}</pre>
67 *
68 * result in the same map being returned.
69 * Instead of a map, you could also define an interface with the methods <tt>getKey1()</tt> and <tt>getKey2</tt> and use
70 * that interface as return type instead of a {@link Map}.
71 * </p>
72 * <p>
73 * In case a lookup does not yield a value from the underlying map or dictionary, the following rules are applied:
74 * <ol>
75 * <li>primitive types yield their default value, as defined by the Java Specification;
76 * <li>string, {@link Class}es and enum values yield <code>null</code>;
77 * <li>for arrays, collections and maps, an empty array/collection/map is returned;
78 * <li>for other interface types that are treated as configuration type a null-object is returned.
79 * </ol>
80 * </p>
81 *
82 * <b> Sample codes: </b>
83 *
84 * <p> Code example with a component that defines a Configuration Dependency using a specific callback method reference,
85 * and the method accepts in argument a configuration type (the pid is assumed to be the fqdn of the configuration type):
Pierre De Ropfaca2892016-01-31 23:27:05 +000086 *
87 * <pre> {@code
88 * public class Activator extends DependencyManagerActivator {
Pierre De Rop11527502016-02-18 21:07:16 +000089 * public void init(BundleContext ctx, DependencyManager dm) throws Exception {
Pierre De Ropfaca2892016-01-31 23:27:05 +000090 * component(comp -> comp
91 * .impl(ServiceImpl.class)
Pierre De Rop11527502016-02-18 21:07:16 +000092 * .withConf(conf -> conf.update(MyConfig.class, ServiceImpl::modified)));
93 * }
94 * }
95 * }</pre>
96 *
97 * <p> Code example with a component that defines a Configuration Dependency using a specific callback method reference
98 * which accepts a Dictionary in argument:
99 *
100 * <pre> {@code
101 * public class Activator extends DependencyManagerActivator {
102 * public void init(BundleContext ctx, DependencyManager dm) throws Exception {
103 * component(comp -> comp
104 * .impl(ServiceImpl.class)
105 * .withConf(conf -> conf.pid("my.pid").update(ServiceImpl::modified)));
106 * }
107 * }
108 * }</pre>
109 *
110 * <p> Code example which defines a configuration dependency injected in the "ServiceImpl.updated(Dictionary)" callback:
111 *
112 * <pre> {@code
113 * public class Activator extends DependencyManagerActivator {
114 * public void init(BundleContext ctx, DependencyManager dm) throws Exception {
115 * component(comp -> comp.impl(ServiceImpl.class).withConf("my.pid"));
116 * }
117 * }
118 * }</pre>
119 *
120 * <p> Code example with a component that defines a Configuration Dependency using a specific callback method name:
121 *
122 * <pre> {@code
123 * public class Activator extends DependencyManagerActivator {
124 * public void init(BundleContext ctx, DependencyManager dm) throws Exception {
125 * component(comp -> comp.impl(ServiceImpl.class).withConf(conf -> conf.pid("my.pid").update("modified")));
Pierre De Ropfaca2892016-01-31 23:27:05 +0000126 * }
127 * }
128 * }</pre>
129 *
130 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
131 */
132public interface ConfigurationDependencyBuilder extends DependencyBuilder<ConfigurationDependency> {
133 /**
134 * Sets the pid for this configuration dependency.
135 *
Pierre De Rop11527502016-02-18 21:07:16 +0000136 * @param pid the configuration dependency pid.
Pierre De Ropfaca2892016-01-31 23:27:05 +0000137 * @return this builder
138 */
139 ConfigurationDependencyBuilder pid(String pid);
140
141 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000142 * Sets propagation of the configuration to the service properties (false by default).
Pierre De Ropfaca2892016-01-31 23:27:05 +0000143 * All public configuration properties (not starting with a dot) will be propagated to the component service properties.
144 *
145 * @return this builder
146 */
147 ConfigurationDependencyBuilder propagate();
148
149 /**
150 * Sets propagation of the configuration properties to the service properties (false by default).
151 *
152 * @param propagate true if all public configuration properties (not starting with a dot) must be propagated to the component service properties (false by default)
153 * @return this builder
154 */
155 ConfigurationDependencyBuilder propagate(boolean propagate);
Pierre De Rop11527502016-02-18 21:07:16 +0000156
Pierre De Ropfaca2892016-01-31 23:27:05 +0000157 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000158 * Sets a callback method to call on the component implementation class(es) when the configuration is updated. When the configuration is lost, the callback is invoked
159 * with a null dictionary. The following callback signatures are supported and searched in the following order:
160 * <ol>
161 * <li>method(Dictionary)</li>
162 * <li>method(Component, Dictionary)</li>
163 * </ol>
164 *
165 * @param updateMethod the name of the callback
Pierre De Ropfaca2892016-01-31 23:27:05 +0000166 * @return this builder
167 */
Pierre De Rop11527502016-02-18 21:07:16 +0000168 ConfigurationDependencyBuilder update(String updateMethod);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000169
170 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000171 * Sets a callback method to call on the component implementation class(es) when the configuration is updated. The callback is invoked with a configuration type
172 * argument (null if the configuration is lost).
Pierre De Ropfaca2892016-01-31 23:27:05 +0000173 *
Pierre De Rop11527502016-02-18 21:07:16 +0000174 * @param configType the type of a configuration that is passed as argument to the callback
Pierre De Ropfaca2892016-01-31 23:27:05 +0000175 * @param updateMethod the callback to call on the component instance(s) when the configuration is updated.
176 * @return this builder
177 */
Pierre De Rop11527502016-02-18 21:07:16 +0000178 ConfigurationDependencyBuilder update(Class<?> configType, String updateMethod);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000179
180 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000181 * Sets a callback method to call on a given Object instance when the configuration is updated.
182 * When the updated method is invoked, the Component implementation is not yet instantiated. This method
183 * can be typically used by a Factory object which needs the configuration before it can create the actual
184 * component implementation instance(s).
185 *
186 * When the configuration is lost, the callback is invoked with a null dictionary, and the following signatures are supported:
187 * <ol>
188 * <li>method(Dictionary)</li>
189 * <li>method(Component, Dictionary)</li>
190 * </ol>
Pierre De Ropfaca2892016-01-31 23:27:05 +0000191 *
192 * @param callbackInstance the object instance on which the updatedMethod is invoked
193 * @param updateMethod the callback to call on the callbackInstance when the configuration is updated.
194 * @return this builder
195 */
Pierre De Rop11527502016-02-18 21:07:16 +0000196 ConfigurationDependencyBuilder update(Object callbackInstance, String updateMethod);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000197
198 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000199 * Sets a callback method to call on a given Object instance when the configuration is updated.
200 * When the updated method is invoked, the Component implementation is not yet instantiated. This method
201 * can be typically used by a Factory object which needs the configuration before it can create the actual
202 * component implementation instance(s).
203 * The callback is invoked with a configuration type argument (null of the configuration is lost).
204 *
205 * @param configType the type of a configuration that is passed as argument to the callback
206 * @param callbackInstance the object instance on which the updatedMethod is invoked
207 * @param updateMethod the callback to call on the callbackInstance when the configuration is updated.
Pierre De Ropfaca2892016-01-31 23:27:05 +0000208 * @return this builder
209 */
Pierre De Rop11527502016-02-18 21:07:16 +0000210 ConfigurationDependencyBuilder update(Class<?> configType, Object callbackInstance, String updateMethod);
211
212 /**
213 * Sets a reference to a "callback(Dictionary)" method from one of the component implementation classes.
214 * The method is invoked with a Dictionary argument (which is null if the configuration is lost).
215 *
216 * @param <T> The type of the target component implementation class on which the method is invoked
217 * @param callback a reference to a method of one of the component implementation classes.
218 * @return this builder
219 */
220 <T> ConfigurationDependencyBuilder update(CbDictionary<T> callback);
221
222 /**
223 * Sets a reference to a "callback(Dictionary, Component)" method from one of the component implementation classes.
224 * The method is invoked with Dictionary/Component arguments. When the configuration is lost, the Dictionary argument
225 * is null.
226 *
227 * @param <T> The type of the target component implementation class on which the method is invoked
228 * @param callback a reference to a method callback defined in one of the the component implementation classes.
229 * @return this builder
230 */
231 <T> ConfigurationDependencyBuilder update(CbDictionaryComponent<T> callback);
232
233 /**
234 * Sets a reference to a "callback(Configuration)" method from one of the component implementation classes.
235 * The method is invoked with a configuration type argument (null if the configuration is lost).
236 *
237 * @param <T> The type of the target component implementation class on which the method is invoked
238 * @param <U> the type of the configuration interface accepted by the callback method.
239 * @param configType the type of a configuration that is passed as argument to the callback
240 * @param callback the callback method reference which must point to a method from one of the component implementation classes. The method
241 * takes as argument an interface which will be implemented by a dynamic proxy that wraps the actual configuration properties.
242 * @return this builder
243 */
244 <T, U> ConfigurationDependencyBuilder update(Class<U> configType, CbConfiguration<T, U> callback);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000245
246 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000247 * Sets a reference to a "callback(configType, Component)" method from one of the component implementation classes.
248 * The method is invoked with two args: configuration type, Component. The configuration type argument is null if the configuration is lost.
Pierre De Ropfaca2892016-01-31 23:27:05 +0000249 *
Pierre De Rop11527502016-02-18 21:07:16 +0000250 * @param <T> The type of the target component implementation class on which the method is invoked
251 * @param <U> the type of the configuration interface accepted by the callback method.
252 * @param configType the type of a configuration that is passed as argument to the callback
253 * @param callback the reference to a method from one of the component implementation classes. The method
254 * takes as argument an interface which will be implemented by a dynamic proxy that wraps the actual configuration properties. It also
255 * takes as the second argument a Component object.
Pierre De Ropfaca2892016-01-31 23:27:05 +0000256 * @return this builder
257 */
Pierre De Rop11527502016-02-18 21:07:16 +0000258 <T, U> ConfigurationDependencyBuilder update(Class<U> configType, CbConfigurationComponent<T, U> callback);
259
Pierre De Ropfaca2892016-01-31 23:27:05 +0000260 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000261 * Sets a reference to a "callback(Dictionary)" method from an Object instance.
Pierre De Ropfaca2892016-01-31 23:27:05 +0000262 *
Pierre De Rop11527502016-02-18 21:07:16 +0000263 * @param callback a reference to an Object instance which takes as argument a Dictionary (null if the configuration is lost).
Pierre De Ropfaca2892016-01-31 23:27:05 +0000264 * @return this builder
265 */
Pierre De Rop11527502016-02-18 21:07:16 +0000266 ConfigurationDependencyBuilder update(InstanceCbDictionary callback);
267
268 /**
269 * Sets a reference to a "callback(Dictionary, Component)" method from an Object instance. The method accepts
270 * a Dictionary and a Component object. The passed Dictionary is null in case the configuration is lost.
271 *
272 * @param callback a reference to method from an Object instance which takes as argument a Dictionary and a Component
273 * @return this builder
274 */
275 ConfigurationDependencyBuilder update(InstanceCbDictionaryComponent callback);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000276
277 /**
Pierre De Rop11527502016-02-18 21:07:16 +0000278 * Sets a reference to a "callback(ConfigType)" method from an Object instance. The configuration type argument is null if the configuration is lost.
279 *
280 * @param <T> the type of the configuration interface accepted by the callback method.
281 * @param configType the class of the configuration that is passed as argument to the callback
282 * @param updated a reference to an Object instance which takes as argument the given configuration type
Pierre De Ropfaca2892016-01-31 23:27:05 +0000283 * @return this builder
284 */
Pierre De Rop11527502016-02-18 21:07:16 +0000285 <T> ConfigurationDependencyBuilder update(Class<T> configType, InstanceCbConfiguration<T> updated);
286
287 /**
288 * Sets a reference to a "callback(Configuration, Component)" method from an Object instance. The method accepts
289 * a configuration type and a Component object. The configuration type argument is null if the configuration is lost.
290 *
291 * @param <T> the type of the configuration interface accepted by the callback method.
292 * @param configType the class of the configuration that is passed as argument to the callback
293 * @param updated a reference to an Object instance which takes as argument a the given configuration type, and a Component object.
294 * @return this builder
295 */
296 <T> ConfigurationDependencyBuilder update(Class<T> configType, InstanceCbConfigurationComponent<T> updated);
Pierre De Ropfaca2892016-01-31 23:27:05 +0000297}
Pierre De Rop11527502016-02-18 21:07:16 +0000298