blob: d747c5911dd550462d7e1d4aa767c17ef511beee [file] [log] [blame]
Pierre De Rop3a00a212015-03-01 09:27:46 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.apache.felix.dm.annotation.api;
20
21import java.lang.annotation.ElementType;
22import java.lang.annotation.Retention;
23import java.lang.annotation.RetentionPolicy;
24import java.lang.annotation.Target;
Pierre De Rop9e5cdba2016-02-17 20:35:16 +000025import java.util.Collection;
26import java.util.Dictionary;
27import java.util.Map;
Pierre De Rop3a00a212015-03-01 09:27:46 +000028
29
30/**
31 * Annotates a method for injecting a Configuration Dependency. A configuration dependency
32 * is always required, and allows you to depend on the availability of a valid configuration
33 * for your component. This dependency requires the OSGi Configuration Admin Service.
34 *
Pierre De Rop9e5cdba2016-02-17 20:35:16 +000035 * The annotation can be applied on a callback method which accepts the following parameters:
36 *
37 * <p><ul>
38 * <li>callback(Dictionary)
39 * <li>callback(Component, Dictionary)
40 * <li>callback(Configuration interface) // type safe configuration
41 * <li>callback(Component, Configuration interface) // type safe configuration
42 * </ul>
43 *
Pierre De Rop3a00a212015-03-01 09:27:46 +000044 * <h3>Usage Examples</h3>
45 *
46 * <p> In the following example, the "Printer" component depends on a configuration
47 * whose PID name is "sample.PrinterConfiguration". This service will initialize
48 * its ip/port number from the provided configuration.
Pierre De Rop9e5cdba2016-02-17 20:35:16 +000049 *
Pierre De Rop3a00a212015-03-01 09:27:46 +000050 * <p> First, we define the configuration metadata, using standard bndtools metatatype annotations
51 * (see http://www.aqute.biz/Bnd/MetaType):
52 *
53 * <blockquote>
54 * <pre>
55 * package sample;
56 * import aQute.bnd.annotation.metatype.Meta.AD;
57 * import aQute.bnd.annotation.metatype.Meta.OCD;
58 *
59 * &#64;OCD(description = "Declare here the Printer Configuration.")
60 * public interface PrinterConfiguration {
61 * &#64;AD(description = "Enter the printer ip address")
62 * String ipAddress();
63 *
64 * &#64;AD(description = "Enter the printer address port number.")
65 * int portNumber();
66 * }
67 * </pre>
68 * </blockquote>
69 *
70 * Next, we define our Printer service which depends on the PrinterConfiguration:
71 *
72 * <blockquote>
73 * <pre>
74 * package sample;
75 * import aQute.bnd.annotation.metatype.*;
76 *
77 * &#64;Component
78 * public class Printer {
Pierre De Rop9e5cdba2016-02-17 20:35:16 +000079 * &#64;ConfigurationDependency // Will use the fqdn of the PrinterConfiguration interface as the pid.
80 * void updated(PrinterConfiguration cnf) {
Pierre De Rop3a00a212015-03-01 09:27:46 +000081 * String ip = cnf.ipAddress();
82 * int port = cnf.portNumber();
83 * ...
84 * }
85 * }
86 * </pre>
87 * </blockquote>
88 *
Pierre De Rop9e5cdba2016-02-17 20:35:16 +000089 * In the above example, the updated callback accepts a type-safe configuration type (and its fqdn is used as the pid).
90 * <p> Configuration type is a new feature that allows you to specify an interface that is implemented
91 * by DM and such interface is then injected to your callback instead of the actual Dictionary.
92 * Using such configuration interface provides a way for creating type-safe configurations from a actual {@link Dictionary} that is
93 * normally injected by Dependency Manager.
94 * The callback accepts in argument an interface that you have to provide, and DM will inject a proxy that converts
95 * method calls from your configuration-type to lookups in the actual map or dictionary. The results of these lookups are then
96 * converted to the expected return type of the invoked configuration method.<br>
97 * As proxies are injected, no implementations of the desired configuration-type are necessary!
98 * </p>
99 * <p>
100 * The lookups performed are based on the name of the method called on the configuration type. The method names are
101 * "mangled" to the following form: <tt>[lower case letter] [any valid character]*</tt>. Method names starting with
102 * <tt>get</tt> or <tt>is</tt> (JavaBean convention) are stripped from these prefixes. For example: given a dictionary
103 * with the key <tt>"foo"</tt> can be accessed from a configuration-type using the following method names:
104 * <tt>foo()</tt>, <tt>getFoo()</tt> and <tt>isFoo()</tt>.
105 * </p>
106 * <p>
107 * The return values supported are: primitive types (or their object wrappers), strings, enums, arrays of
108 * primitives/strings, {@link Collection} types, {@link Map} types, {@link Class}es and interfaces. When an interface is
109 * returned, it is treated equally to a configuration type, that is, it is returned as a proxy.
110 * </p>
111 * <p>
112 * Arrays can be represented either as comma-separated values, optionally enclosed in square brackets. For example:
113 * <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".
114 * Alternatively, you can append the array index to the key in the dictionary to obtain the same: a dictionary with
115 * "arr.0" =&gt; "a", "arr.1" =&gt; "b", "arr.2" =&gt; "c" would result in the same array as the earlier examples.
116 * </p>
117 * <p>
118 * Maps can be represented as single string values similarly as arrays, each value consisting of both the key and value
119 * separated by a dot. Optionally, the value can be enclosed in curly brackets. Similar to array, you can use the same
120 * dot notation using the keys. For example, a dictionary with
121 *
122 * <pre>{@code "map" => "{key1.value1, key2.value2}"}</pre>
123 *
124 * and a dictionary with <p>
125 *
126 * <pre>{@code "map.key1" => "value1", "map2.key2" => "value2"}</pre>
127 *
128 * result in the same map being returned.
129 * Instead of a map, you could also define an interface with the methods <tt>getKey1()</tt> and <tt>getKey2</tt> and use
130 * that interface as return type instead of a {@link Map}.
131 * </p>
132 * <p>
133 * In case a lookup does not yield a value from the underlying map or dictionary, the following rules are applied:
134 * <ol>
135 * <li>primitive types yield their default value, as defined by the Java Specification;
136 * <li>string, {@link Class}es and enum values yield <code>null</code>;
137 * <li>for arrays, collections and maps, an empty array/collection/map is returned;
138 * <li>for other interface types that are treated as configuration type a null-object is returned.
139 * </ol>
140 * </p>
141 *
Pierre De Rop3a00a212015-03-01 09:27:46 +0000142 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
143 */
144@Retention(RetentionPolicy.CLASS)
145@Target(ElementType.METHOD)
146public @interface ConfigurationDependency
147{
148 /**
149 * Returns the pid for a given service (by default, the pid is the service class name).
150 * @return the pid for a given service (default = Service class name)
151 */
152 String pid() default "";
153
154 /**
155 * Returns the pid from a class name. The full class name will be used as the configuration PID.
Pierre De Rop40ecace2016-02-09 21:44:38 +0000156 * You can use this method when you use an interface annotated with standard bndtols metatype annotations.
Pierre De Rop3a00a212015-03-01 09:27:46 +0000157 * (see http://www.aqute.biz/Bnd/MetaType).
Pierre De Rop1c0431f2016-02-06 23:28:44 +0000158 * @return the pid class
Pierre De Rop9e5cdba2016-02-17 20:35:16 +0000159 * @deprecated just define an updated callback which accepts as argument a configuration type.
Pierre De Rop3a00a212015-03-01 09:27:46 +0000160 */
161 Class<?> pidClass() default Object.class;
Pierre De Rop9e5cdba2016-02-17 20:35:16 +0000162
Pierre De Rop3a00a212015-03-01 09:27:46 +0000163 /**
164 * Returns true if the configuration properties must be published along with the service.
165 * Any additional service properties specified directly are merged with these.
166 * @return true if configuration must be published along with the service, false if not.
167 */
168 boolean propagate() default false;
169
170 /**
171 * The name for this configuration dependency. When you give a name a dependency, it won't be evaluated
172 * immediately, but after the component's init method has been called, and from the init method, you can then return
173 * a map in order to dynamically configure the configuration dependency (the map has to contain a "pid" and/or "propagate"
174 * flag, prefixed with the dependency name). Then the dependency will be evaluated after the component init method, and will
175 * be injected before the start method.
176 *
177 * <p> Usage example of a Configuration dependency whose pid and propagate flag is configured dynamically from init method:
178 *
179 * <blockquote><pre>
180 * &#47;**
181 * * A Service that dynamically defines an extra dynamic configuration dependency from its init method.
182 * *&#47;
183 * &#64;Component
184 * class X {
185 * private Dictionary m_config;
186 *
187 * // Inject initial Configuration (injected before any other required dependencies)
188 * &#64;ConfigurationDependency
189 * void componentConfiguration(Dictionary config) {
190 * // you must throw an exception if the configuration is not valid
191 * m_config = config;
192 * }
193 *
194 * &#47;**
195 * * All unnamed dependencies are injected: we can now configure our dynamic configuration whose dependency name is "global".
196 * *&#47;
197 * &#64;Init
198 * Map init() {
199 * return new HashMap() {{
200 * put("global.pid", m_config.get("globalConfig.pid"));
201 * put("global.propagate", m_config.get("globalConfig.propagate"));
202 * }};
203 * }
204 *
205 * // Injected after init, and dynamically configured by the init method.
206 * &#64;ConfigurationDependency(name="global")
207 * void globalConfiguration(Dictionary globalConfig) {
208 * // you must throw an exception if the configuration is not valid
209 * }
210 *
211 * &#47;**
212 * * All dependencies are injected and our service is now ready to be published.
213 * *&#47;
214 * &#64;Start
215 * void start() {
216 * }
217 * }
218 * </pre></blockquote>
Pierre De Rop1c0431f2016-02-06 23:28:44 +0000219 * @return the dependency name used to configure the dependency dynamically from init callback
Pierre De Rop3a00a212015-03-01 09:27:46 +0000220 */
221 String name() default "";
222
223 /**
224 * The label used to display the tab name (or section) where the properties are displayed. Example: "Printer Service".
225 * @return The label used to display the tab name where the properties are displayed.
226 * @deprecated use standard bndtools metatype annotations instead (see http://www.aqute.biz/Bnd/MetaType)
227 */
228 String heading() default "";
229
230 /**
231 * A human readable description of the PID this annotation is associated with. Example: "Configuration for the PrinterService bundle".
232 * @return A human readable description of the PID this annotation is associated with.
233 * @deprecated use standard bndtools metatype annotations instead (see http://www.aqute.biz/Bnd/MetaType)
234 */
235 String description() default "";
236
237 /**
238 * The list of properties types used to expose properties in web console.
239 * @return The list of properties types used to expose properties in web console.
240 * @deprecated use standard bndtools metatype annotations instead (see http://www.aqute.biz/Bnd/MetaType)
241 */
242 PropertyMetaData[] metadata() default {};
243}