blob: b58b7751737ca6ac505b32de4825245fea541a3e [file] [log] [blame]
Stuart McCullochf3173222012-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 McCulloch42151ee2012-07-16 13:43:38 +00008import aQute.bnd.osgi.*;
9import aQute.bnd.osgi.Descriptors.TypeRef;
Stuart McCullochcd1ddd72012-07-19 13:11:20 +000010import aQute.bnd.version.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000011import aQute.lib.collections.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000012import aQute.lib.tag.*;
Stuart McCullochf3173222012-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 McCulloch4482c702012-06-15 13:27:53 +000024 final MultiMap<String,String> property = new MultiMap<String,String>();
Stuart McCulloch5515a832012-07-22 00:19:13 +000025 final Map<String,ReferenceDef> references = new LinkedHashMap<String,ReferenceDef>();
Stuart McCullochf3173222012-06-07 21:57:32 +000026
Stuart McCulloch5515a832012-07-22 00:19:13 +000027 Version version = AnnotationReader.V1_0;
Stuart McCullochf3173222012-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
53 for (ReferenceDef ref : references.values()) {
54 ref.prepare(analyzer);
55 if (ref.version.compareTo(version) > 0)
56 version = ref.version;
57 }
58
59 if (implementation == null) {
60 analyzer.error("No Implementation defined for component " + name);
61 return;
62 }
63
64 analyzer.referTo(implementation);
65
66 if (name == null)
67 name = implementation.getFQN();
68
69 if (service != null && service.length > 0) {
70 for (TypeRef interfaceName : service)
71 analyzer.referTo(interfaceName);
72 } else if (servicefactory != null && servicefactory)
73 analyzer.warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
74
Stuart McCulloch5515a832012-07-22 00:19:13 +000075 if (configurationPolicy != null)
76 version = ReferenceDef.max(version, AnnotationReader.V1_1);
Stuart McCullochf3173222012-06-07 21:57:32 +000077 if (configurationPid != null)
78 version = ReferenceDef.max(version, AnnotationReader.V1_2);
79
Stuart McCulloch4482c702012-06-15 13:27:53 +000080 for (Map.Entry<String,List<String>> kvs : property.entrySet()) {
Stuart McCullochf3173222012-06-07 21:57:32 +000081 Tag property = new Tag("property");
82 String name = kvs.getKey();
83 String type = null;
84 int n = name.indexOf(':');
85 if (n > 0) {
86 type = name.substring(n + 1);
87 name = name.substring(0, n);
88 }
89
90 property.addAttribute("name", name);
91 if (type != null) {
92 property.addAttribute("type", type);
93 }
94 if (kvs.getValue().size() == 1) {
95 String value = kvs.getValue().get(0);
96 value = check(type, value, analyzer);
97 property.addAttribute("value", value);
98 } else {
99 StringBuilder sb = new StringBuilder();
100
101 String del = "";
102 for (String v : kvs.getValue()) {
103 sb.append(del);
104 v = check(type, v, analyzer);
105 sb.append(v);
106 del = "\n";
107 }
108 property.addContent(sb.toString());
109 }
110 propertyTags.add(property);
111 }
112 }
Stuart McCulloch5515a832012-07-22 00:19:13 +0000113
114 void sortReferences() {
115 Map<String, ReferenceDef> temp = new TreeMap(references);
116 references.clear();
117 references.putAll(temp);
118 }
Stuart McCullochf3173222012-06-07 21:57:32 +0000119
120 /**
121 * Returns a tag describing the component element.
122 *
123 * @return a component element
124 */
125 Tag getTag() {
Stuart McCulloch5515a832012-07-22 00:19:13 +0000126 String xmlns = this.xmlns;
127 if (xmlns == null && version != AnnotationReader.V1_0)
128 xmlns = NAMESPACE_STEM + "/v" + version;
129 Tag component = new Tag(xmlns == null? "component": "scr:component");
Stuart McCullochf3173222012-06-07 21:57:32 +0000130 if (xmlns != null)
131 component.addAttribute("xmlns:scr", xmlns);
Stuart McCullochf3173222012-06-07 21:57:32 +0000132
133 component.addAttribute("name", name);
134
135 if (servicefactory != null)
136 component.addAttribute("servicefactory", servicefactory);
137
138 if (configurationPolicy != null)
Stuart McCulloch4482c702012-06-15 13:27:53 +0000139 component.addAttribute("configuration-policy", configurationPolicy.toString().toLowerCase());
Stuart McCullochf3173222012-06-07 21:57:32 +0000140
141 if (enabled != null)
142 component.addAttribute("enabled", enabled);
143
144 if (immediate != null)
145 component.addAttribute("immediate", immediate);
146
147 if (factory != null)
148 component.addAttribute("factory", factory);
149
150 if (activate != null)
151 component.addAttribute("activate", activate);
152
153 if (deactivate != null)
154 component.addAttribute("deactivate", deactivate);
155
156 if (modified != null)
157 component.addAttribute("modified", modified);
158
159 if (configurationPid != null)
160 component.addAttribute("configuration-pid", configurationPid);
161
162 Tag impl = new Tag(component, "implementation");
163 impl.addAttribute("class", implementation.getFQN());
164
165 if (service != null && service.length != 0) {
166 Tag s = new Tag(component, "service");
167 if (servicefactory != null && servicefactory)
168 s.addAttribute("servicefactory", true);
169
170 for (TypeRef ss : service) {
171 Tag provide = new Tag(s, "provide");
172 provide.addAttribute("interface", ss.getFQN());
173 }
174 }
175
176 for (ReferenceDef ref : references.values()) {
177 Tag refTag = ref.getTag();
178 component.addContent(refTag);
179 }
180
181 for (Tag tag : propertyTags)
182 component.addContent(tag);
183
184 for (String entry : properties) {
185 Tag properties = new Tag(component, "properties");
186 properties.addAttribute("entry", entry);
187 }
188 return component;
189 }
190
191 private String check(String type, String v, Analyzer analyzer) {
192 if (type == null)
193 return v;
194
195 try {
Stuart McCullochcd1ddd72012-07-19 13:11:20 +0000196 if ( type.equals("Char"))
197 type = "Character";
198
Stuart McCulloch4482c702012-06-15 13:27:53 +0000199 Class< ? > c = Class.forName("java.lang." + type);
Stuart McCullochf3173222012-06-07 21:57:32 +0000200 if (c == String.class)
201 return v;
202
203 v = v.trim();
204 if (c == Character.class)
205 c = Integer.class;
206 Method m = c.getMethod("valueOf", String.class);
207 m.invoke(null, v);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000208 }
209 catch (ClassNotFoundException e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000210 analyzer.error("Invalid data type %s", type);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000211 }
212 catch (NoSuchMethodException e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000213 analyzer.error("Cannot convert data %s to type %s", v, type);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000214 }
215 catch (NumberFormatException e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000216 analyzer.error("Not a valid number %s for %s, %s", v, type, e.getMessage());
Stuart McCulloch4482c702012-06-15 13:27:53 +0000217 }
218 catch (Exception e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000219 analyzer.error("Cannot convert data %s to type %s", v, type);
220 }
221 return v;
222 }
223}