blob: 8c4b090b6e979ff7ce0143e9981868a1893b5470 [file] [log] [blame]
Stuart McCullochbb014372012-06-07 21:57:32 +00001package aQute.bnd.component;
2
3import java.lang.reflect.*;
4import java.util.*;
5
6import org.osgi.service.component.annotations.*;
7
Stuart McCulloch39cc9ac2012-07-16 13:43:38 +00008import aQute.bnd.osgi.*;
9import aQute.bnd.osgi.Descriptors.TypeRef;
Stuart McCulloch6a046662012-07-19 13:11:20 +000010import aQute.bnd.version.*;
Stuart McCullochbb014372012-06-07 21:57:32 +000011import aQute.lib.collections.*;
Stuart McCullochbb014372012-06-07 21:57:32 +000012import aQute.lib.tag.*;
Stuart McCullochbb014372012-06-07 21:57:32 +000013
14/**
15 * This class just holds the information for the component, implementation, and
16 * service/provide elements. The {@link #prepare(Analyzer)} method will check if
17 * things are ok and the {@link #getTag()} method returns a tag if the prepare
18 * method returns without any errors. The class uses {@link ReferenceDef} to
19 * hold the references.
20 */
21class ComponentDef {
22 final static String NAMESPACE_STEM = "http://www.osgi.org/xmlns/scr";
23 final List<String> properties = new ArrayList<String>();
Stuart McCulloch2286f232012-06-15 13:27:53 +000024 final MultiMap<String,String> property = new MultiMap<String,String>();
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +000025 final Map<String,ReferenceDef> references = new LinkedHashMap<String,ReferenceDef>();
Stuart McCullochbb014372012-06-07 21:57:32 +000026
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +000027 Version version = AnnotationReader.V1_0;
Stuart McCullochbb014372012-06-07 21:57:32 +000028 String name;
29 String factory;
30 Boolean immediate;
31 Boolean servicefactory;
32 ConfigurationPolicy configurationPolicy;
33 TypeRef implementation;
34 TypeRef service[];
35 String activate;
36 String deactivate;
37 String modified;
38 Boolean enabled;
39 String xmlns;
40 String configurationPid;
41 List<Tag> propertyTags = new ArrayList<Tag>();
42
43 /**
44 * Called to prepare. If will look for any errors or inconsistencies in the
45 * setup.
46 *
47 * @param analyzer
48 * the analyzer to report errors and create references
49 * @throws Exception
50 */
51 void prepare(Analyzer analyzer) throws Exception {
52
Stuart McCullochec47fe72012-09-19 12:56:05 +000053 prepareVersion(analyzer);
54
Stuart McCullochbb014372012-06-07 21:57:32 +000055
56 if (implementation == null) {
57 analyzer.error("No Implementation defined for component " + name);
58 return;
59 }
60
61 analyzer.referTo(implementation);
62
63 if (name == null)
64 name = implementation.getFQN();
65
66 if (service != null && service.length > 0) {
67 for (TypeRef interfaceName : service)
68 analyzer.referTo(interfaceName);
69 } else if (servicefactory != null && servicefactory)
70 analyzer.warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
71
Stuart McCulloch2286f232012-06-15 13:27:53 +000072 for (Map.Entry<String,List<String>> kvs : property.entrySet()) {
Stuart McCullochbb014372012-06-07 21:57:32 +000073 Tag property = new Tag("property");
74 String name = kvs.getKey();
75 String type = null;
76 int n = name.indexOf(':');
77 if (n > 0) {
78 type = name.substring(n + 1);
79 name = name.substring(0, n);
80 }
81
82 property.addAttribute("name", name);
83 if (type != null) {
84 property.addAttribute("type", type);
85 }
86 if (kvs.getValue().size() == 1) {
87 String value = kvs.getValue().get(0);
88 value = check(type, value, analyzer);
89 property.addAttribute("value", value);
90 } else {
91 StringBuilder sb = new StringBuilder();
92
93 String del = "";
94 for (String v : kvs.getValue()) {
95 sb.append(del);
96 v = check(type, v, analyzer);
97 sb.append(v);
98 del = "\n";
99 }
100 property.addContent(sb.toString());
101 }
102 propertyTags.add(property);
103 }
104 }
Stuart McCullochec47fe72012-09-19 12:56:05 +0000105
106 private void prepareVersion(Analyzer analyzer) throws Exception {
107
108 for (ReferenceDef ref : references.values()) {
109 ref.prepare(analyzer);
110 updateVersion(ref.version);
111 }
112 if (configurationPolicy != null)
113 updateVersion(AnnotationReader.V1_1);
114 if (configurationPid != null)
115 updateVersion(AnnotationReader.V1_2);
116 if (modified != null)
117 updateVersion(AnnotationReader.V1_1);
118
119 }
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000120
121 void sortReferences() {
Stuart McCullochb215bfd2012-09-06 18:28:06 +0000122 Map<String, ReferenceDef> temp = new TreeMap<String,ReferenceDef>(references);
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000123 references.clear();
124 references.putAll(temp);
125 }
Stuart McCullochbb014372012-06-07 21:57:32 +0000126
127 /**
128 * Returns a tag describing the component element.
129 *
130 * @return a component element
131 */
132 Tag getTag() {
Stuart McCulloch4b9de8e2012-07-22 00:19:13 +0000133 String xmlns = this.xmlns;
134 if (xmlns == null && version != AnnotationReader.V1_0)
135 xmlns = NAMESPACE_STEM + "/v" + version;
136 Tag component = new Tag(xmlns == null? "component": "scr:component");
Stuart McCullochbb014372012-06-07 21:57:32 +0000137 if (xmlns != null)
138 component.addAttribute("xmlns:scr", xmlns);
Stuart McCullochbb014372012-06-07 21:57:32 +0000139
140 component.addAttribute("name", name);
141
142 if (servicefactory != null)
143 component.addAttribute("servicefactory", servicefactory);
144
145 if (configurationPolicy != null)
Stuart McCulloch2286f232012-06-15 13:27:53 +0000146 component.addAttribute("configuration-policy", configurationPolicy.toString().toLowerCase());
Stuart McCullochbb014372012-06-07 21:57:32 +0000147
148 if (enabled != null)
149 component.addAttribute("enabled", enabled);
150
151 if (immediate != null)
152 component.addAttribute("immediate", immediate);
153
154 if (factory != null)
155 component.addAttribute("factory", factory);
156
Stuart McCullochec47fe72012-09-19 12:56:05 +0000157 if (activate != null && version != AnnotationReader.V1_0)
Stuart McCullochbb014372012-06-07 21:57:32 +0000158 component.addAttribute("activate", activate);
159
Stuart McCullochec47fe72012-09-19 12:56:05 +0000160 if (deactivate != null && version != AnnotationReader.V1_0)
Stuart McCullochbb014372012-06-07 21:57:32 +0000161 component.addAttribute("deactivate", deactivate);
162
163 if (modified != null)
164 component.addAttribute("modified", modified);
165
166 if (configurationPid != null)
167 component.addAttribute("configuration-pid", configurationPid);
168
169 Tag impl = new Tag(component, "implementation");
170 impl.addAttribute("class", implementation.getFQN());
171
172 if (service != null && service.length != 0) {
173 Tag s = new Tag(component, "service");
174 if (servicefactory != null && servicefactory)
175 s.addAttribute("servicefactory", true);
176
177 for (TypeRef ss : service) {
178 Tag provide = new Tag(s, "provide");
179 provide.addAttribute("interface", ss.getFQN());
180 }
181 }
182
183 for (ReferenceDef ref : references.values()) {
184 Tag refTag = ref.getTag();
185 component.addContent(refTag);
186 }
187
188 for (Tag tag : propertyTags)
189 component.addContent(tag);
190
191 for (String entry : properties) {
192 Tag properties = new Tag(component, "properties");
193 properties.addAttribute("entry", entry);
194 }
195 return component;
196 }
197
198 private String check(String type, String v, Analyzer analyzer) {
199 if (type == null)
200 return v;
201
202 try {
Stuart McCulloch6a046662012-07-19 13:11:20 +0000203 if ( type.equals("Char"))
204 type = "Character";
205
Stuart McCulloch2286f232012-06-15 13:27:53 +0000206 Class< ? > c = Class.forName("java.lang." + type);
Stuart McCullochbb014372012-06-07 21:57:32 +0000207 if (c == String.class)
208 return v;
209
210 v = v.trim();
211 if (c == Character.class)
212 c = Integer.class;
213 Method m = c.getMethod("valueOf", String.class);
214 m.invoke(null, v);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000215 }
216 catch (ClassNotFoundException e) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000217 analyzer.error("Invalid data type %s", type);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000218 }
219 catch (NoSuchMethodException e) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000220 analyzer.error("Cannot convert data %s to type %s", v, type);
Stuart McCulloch2286f232012-06-15 13:27:53 +0000221 }
222 catch (NumberFormatException e) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000223 analyzer.error("Not a valid number %s for %s, %s", v, type, e.getMessage());
Stuart McCulloch2286f232012-06-15 13:27:53 +0000224 }
225 catch (Exception e) {
Stuart McCullochbb014372012-06-07 21:57:32 +0000226 analyzer.error("Cannot convert data %s to type %s", v, type);
227 }
228 return v;
229 }
Stuart McCullochec47fe72012-09-19 12:56:05 +0000230
231 void updateVersion(Version version) {
232 this.version = max(this.version, version);
233 }
234
235 static <T extends Comparable<T>> T max(T a, T b) {
236 int n = a.compareTo(b);
237 if (n >= 0)
238 return a;
239 return b;
240 }
241
Stuart McCullochbb014372012-06-07 21:57:32 +0000242}