blob: 98f7d363496b2f1b5aa309b3fe86eb2a460f02eb [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 McCullochf3173222012-06-07 21:57:32 +000010import aQute.lib.collections.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000011import aQute.lib.tag.*;
Stuart McCullochf3173222012-06-07 21:57:32 +000012
13/**
14 * This class just holds the information for the component, implementation, and
15 * service/provide elements. The {@link #prepare(Analyzer)} method will check if
16 * things are ok and the {@link #getTag()} method returns a tag if the prepare
17 * method returns without any errors. The class uses {@link ReferenceDef} to
18 * hold the references.
19 */
20class ComponentDef {
21 final static String NAMESPACE_STEM = "http://www.osgi.org/xmlns/scr";
22 final List<String> properties = new ArrayList<String>();
Stuart McCulloch4482c702012-06-15 13:27:53 +000023 final MultiMap<String,String> property = new MultiMap<String,String>();
24 final Map<String,ReferenceDef> references = new TreeMap<String,ReferenceDef>();
Stuart McCullochf3173222012-06-07 21:57:32 +000025
26 Version version = AnnotationReader.V1_1;
27 String name;
28 String factory;
29 Boolean immediate;
30 Boolean servicefactory;
31 ConfigurationPolicy configurationPolicy;
32 TypeRef implementation;
33 TypeRef service[];
34 String activate;
35 String deactivate;
36 String modified;
37 Boolean enabled;
38 String xmlns;
39 String configurationPid;
40 List<Tag> propertyTags = new ArrayList<Tag>();
41
42 /**
43 * Called to prepare. If will look for any errors or inconsistencies in the
44 * setup.
45 *
46 * @param analyzer
47 * the analyzer to report errors and create references
48 * @throws Exception
49 */
50 void prepare(Analyzer analyzer) throws Exception {
51
52 for (ReferenceDef ref : references.values()) {
53 ref.prepare(analyzer);
54 if (ref.version.compareTo(version) > 0)
55 version = ref.version;
56 }
57
58 if (implementation == null) {
59 analyzer.error("No Implementation defined for component " + name);
60 return;
61 }
62
63 analyzer.referTo(implementation);
64
65 if (name == null)
66 name = implementation.getFQN();
67
68 if (service != null && service.length > 0) {
69 for (TypeRef interfaceName : service)
70 analyzer.referTo(interfaceName);
71 } else if (servicefactory != null && servicefactory)
72 analyzer.warning("The servicefactory:=true directive is set but no service is provided, ignoring it");
73
74 if (configurationPid != null)
75 version = ReferenceDef.max(version, AnnotationReader.V1_2);
76
Stuart McCulloch4482c702012-06-15 13:27:53 +000077 for (Map.Entry<String,List<String>> kvs : property.entrySet()) {
Stuart McCullochf3173222012-06-07 21:57:32 +000078 Tag property = new Tag("property");
79 String name = kvs.getKey();
80 String type = null;
81 int n = name.indexOf(':');
82 if (n > 0) {
83 type = name.substring(n + 1);
84 name = name.substring(0, n);
85 }
86
87 property.addAttribute("name", name);
88 if (type != null) {
89 property.addAttribute("type", type);
90 }
91 if (kvs.getValue().size() == 1) {
92 String value = kvs.getValue().get(0);
93 value = check(type, value, analyzer);
94 property.addAttribute("value", value);
95 } else {
96 StringBuilder sb = new StringBuilder();
97
98 String del = "";
99 for (String v : kvs.getValue()) {
100 sb.append(del);
101 v = check(type, v, analyzer);
102 sb.append(v);
103 del = "\n";
104 }
105 property.addContent(sb.toString());
106 }
107 propertyTags.add(property);
108 }
109 }
110
111 /**
112 * Returns a tag describing the component element.
113 *
114 * @return a component element
115 */
116 Tag getTag() {
117 Tag component = new Tag("scr:component");
118 if (xmlns != null)
119 component.addAttribute("xmlns:scr", xmlns);
120 else
121 component.addAttribute("xmlns:scr", NAMESPACE_STEM + "/v" + version);
122
123 component.addAttribute("name", name);
124
125 if (servicefactory != null)
126 component.addAttribute("servicefactory", servicefactory);
127
128 if (configurationPolicy != null)
Stuart McCulloch4482c702012-06-15 13:27:53 +0000129 component.addAttribute("configuration-policy", configurationPolicy.toString().toLowerCase());
Stuart McCullochf3173222012-06-07 21:57:32 +0000130
131 if (enabled != null)
132 component.addAttribute("enabled", enabled);
133
134 if (immediate != null)
135 component.addAttribute("immediate", immediate);
136
137 if (factory != null)
138 component.addAttribute("factory", factory);
139
140 if (activate != null)
141 component.addAttribute("activate", activate);
142
143 if (deactivate != null)
144 component.addAttribute("deactivate", deactivate);
145
146 if (modified != null)
147 component.addAttribute("modified", modified);
148
149 if (configurationPid != null)
150 component.addAttribute("configuration-pid", configurationPid);
151
152 Tag impl = new Tag(component, "implementation");
153 impl.addAttribute("class", implementation.getFQN());
154
155 if (service != null && service.length != 0) {
156 Tag s = new Tag(component, "service");
157 if (servicefactory != null && servicefactory)
158 s.addAttribute("servicefactory", true);
159
160 for (TypeRef ss : service) {
161 Tag provide = new Tag(s, "provide");
162 provide.addAttribute("interface", ss.getFQN());
163 }
164 }
165
166 for (ReferenceDef ref : references.values()) {
167 Tag refTag = ref.getTag();
168 component.addContent(refTag);
169 }
170
171 for (Tag tag : propertyTags)
172 component.addContent(tag);
173
174 for (String entry : properties) {
175 Tag properties = new Tag(component, "properties");
176 properties.addAttribute("entry", entry);
177 }
178 return component;
179 }
180
181 private String check(String type, String v, Analyzer analyzer) {
182 if (type == null)
183 return v;
184
185 try {
Stuart McCulloch4482c702012-06-15 13:27:53 +0000186 Class< ? > c = Class.forName("java.lang." + type);
Stuart McCullochf3173222012-06-07 21:57:32 +0000187 if (c == String.class)
188 return v;
189
190 v = v.trim();
191 if (c == Character.class)
192 c = Integer.class;
193 Method m = c.getMethod("valueOf", String.class);
194 m.invoke(null, v);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000195 }
196 catch (ClassNotFoundException e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000197 analyzer.error("Invalid data type %s", type);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000198 }
199 catch (NoSuchMethodException e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000200 analyzer.error("Cannot convert data %s to type %s", v, type);
Stuart McCulloch4482c702012-06-15 13:27:53 +0000201 }
202 catch (NumberFormatException e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000203 analyzer.error("Not a valid number %s for %s, %s", v, type, e.getMessage());
Stuart McCulloch4482c702012-06-15 13:27:53 +0000204 }
205 catch (Exception e) {
Stuart McCullochf3173222012-06-07 21:57:32 +0000206 analyzer.error("Cannot convert data %s to type %s", v, type);
207 }
208 return v;
209 }
210}