blob: 75b7b739d81d8490ae7071280aa6047a65cca30f [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
8import aQute.lib.collections.*;
9import aQute.lib.osgi.*;
10import aQute.lib.osgi.Descriptors.TypeRef;
11import aQute.lib.tag.*;
12import aQute.libg.version.*;
13
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>();
24 final MultiMap<String, String> property = new MultiMap<String, String>();
25 final Map<String, ReferenceDef> references = new TreeMap<String, ReferenceDef>();
26
27 Version version = AnnotationReader.V1_1;
28 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
75 if (configurationPid != null)
76 version = ReferenceDef.max(version, AnnotationReader.V1_2);
77
78 for (Map.Entry<String, List<String>> kvs : property.entrySet()) {
79 Tag property = new Tag("property");
80 String name = kvs.getKey();
81 String type = null;
82 int n = name.indexOf(':');
83 if (n > 0) {
84 type = name.substring(n + 1);
85 name = name.substring(0, n);
86 }
87
88 property.addAttribute("name", name);
89 if (type != null) {
90 property.addAttribute("type", type);
91 }
92 if (kvs.getValue().size() == 1) {
93 String value = kvs.getValue().get(0);
94 value = check(type, value, analyzer);
95 property.addAttribute("value", value);
96 } else {
97 StringBuilder sb = new StringBuilder();
98
99 String del = "";
100 for (String v : kvs.getValue()) {
101 sb.append(del);
102 v = check(type, v, analyzer);
103 sb.append(v);
104 del = "\n";
105 }
106 property.addContent(sb.toString());
107 }
108 propertyTags.add(property);
109 }
110 }
111
112 /**
113 * Returns a tag describing the component element.
114 *
115 * @return a component element
116 */
117 Tag getTag() {
118 Tag component = new Tag("scr:component");
119 if (xmlns != null)
120 component.addAttribute("xmlns:scr", xmlns);
121 else
122 component.addAttribute("xmlns:scr", NAMESPACE_STEM + "/v" + version);
123
124 component.addAttribute("name", name);
125
126 if (servicefactory != null)
127 component.addAttribute("servicefactory", servicefactory);
128
129 if (configurationPolicy != null)
130 component.addAttribute("configuration-policy", configurationPolicy.toString()
131 .toLowerCase());
132
133 if (enabled != null)
134 component.addAttribute("enabled", enabled);
135
136 if (immediate != null)
137 component.addAttribute("immediate", immediate);
138
139 if (factory != null)
140 component.addAttribute("factory", factory);
141
142 if (activate != null)
143 component.addAttribute("activate", activate);
144
145 if (deactivate != null)
146 component.addAttribute("deactivate", deactivate);
147
148 if (modified != null)
149 component.addAttribute("modified", modified);
150
151 if (configurationPid != null)
152 component.addAttribute("configuration-pid", configurationPid);
153
154 Tag impl = new Tag(component, "implementation");
155 impl.addAttribute("class", implementation.getFQN());
156
157 if (service != null && service.length != 0) {
158 Tag s = new Tag(component, "service");
159 if (servicefactory != null && servicefactory)
160 s.addAttribute("servicefactory", true);
161
162 for (TypeRef ss : service) {
163 Tag provide = new Tag(s, "provide");
164 provide.addAttribute("interface", ss.getFQN());
165 }
166 }
167
168 for (ReferenceDef ref : references.values()) {
169 Tag refTag = ref.getTag();
170 component.addContent(refTag);
171 }
172
173 for (Tag tag : propertyTags)
174 component.addContent(tag);
175
176 for (String entry : properties) {
177 Tag properties = new Tag(component, "properties");
178 properties.addAttribute("entry", entry);
179 }
180 return component;
181 }
182
183 private String check(String type, String v, Analyzer analyzer) {
184 if (type == null)
185 return v;
186
187 try {
188 Class<?> c = Class.forName("java.lang." + type);
189 if (c == String.class)
190 return v;
191
192 v = v.trim();
193 if (c == Character.class)
194 c = Integer.class;
195 Method m = c.getMethod("valueOf", String.class);
196 m.invoke(null, v);
197 } catch (ClassNotFoundException e) {
198 analyzer.error("Invalid data type %s", type);
199 } catch (NoSuchMethodException e) {
200 analyzer.error("Cannot convert data %s to type %s", v, type);
201 } catch (NumberFormatException e) {
202 analyzer.error("Not a valid number %s for %s, %s", v, type, e.getMessage());
203 } catch (Exception e) {
204 analyzer.error("Cannot convert data %s to type %s", v, type);
205 }
206 return v;
207 }
208}