blob: bf28d428769cf2e6f57c9ef8c0b7aa630dea8b68 [file] [log] [blame]
Clement Escoffierf5fc5562007-08-14 13:44:32 +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.ipojo.manipulation.annotations;
20
21import org.apache.felix.ipojo.metadata.Attribute;
22import org.apache.felix.ipojo.metadata.Element;
23import org.objectweb.asm.AnnotationVisitor;
Clement Escoffier83db4a02008-04-29 22:30:56 +000024import org.objectweb.asm.Type;
Clement Escoffierf5fc5562007-08-14 13:44:32 +000025import org.objectweb.asm.commons.EmptyVisitor;
26
27/**
28 * This class collects method annotations, and give them to the metadata collector.
29 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
30 */
31public class MethodCollector extends EmptyVisitor {
32
33 /**
Clement Escoffier046c1b12007-09-27 12:47:53 +000034 * Parent collector.
Clement Escoffierf5fc5562007-08-14 13:44:32 +000035 */
Clement Escoffier046c1b12007-09-27 12:47:53 +000036 private MetadataCollector m_collector;
Clement Escoffierf5fc5562007-08-14 13:44:32 +000037
38 /**
39 * Method name.
40 */
41 private String m_name;
42
43 /**
44 * Constructor.
45 * @param name : name of the method.
Clement Escoffier046c1b12007-09-27 12:47:53 +000046 * @param collector : parent collector.
Clement Escoffierf5fc5562007-08-14 13:44:32 +000047 */
Clement Escoffier046c1b12007-09-27 12:47:53 +000048 public MethodCollector(String name, MetadataCollector collector) {
49 m_collector = collector;
Clement Escoffierf5fc5562007-08-14 13:44:32 +000050 m_name = name;
51 }
52
53 /**
54 * Visit method annotations.
55 * @param arg0 : annotation name.
56 * @param arg1 : is the annotation visible at runtime.
57 * @return the visitor paring the visited annotation.
58 * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, boolean)
59 */
60 public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
61 if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
62 return processProperty();
63 }
64 if (arg0.equals("Lorg/apache/felix/ipojo/annotations/ServiceProperty;")) {
65 return processServiceProperty();
66 }
67 if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Validate;")) {
68 return processValidate();
69 }
70 if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Invalidate;")) {
71 return processInvalidate();
72 }
73 if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Bind;")) {
74 return processBind("bind");
75 }
76 if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Unbind;")) {
77 return processBind("unbind");
78 }
Clement Escoffier046c1b12007-09-27 12:47:53 +000079
80 if (CustomAnnotationVisitor.isCustomAnnotation(arg0)) {
81 Element elem = CustomAnnotationVisitor.buildElement(arg0);
82 elem.addAttribute(new Attribute("method", m_name));
83 return new CustomAnnotationVisitor(elem, m_collector, true);
84 }
85
Clement Escoffierf5fc5562007-08-14 13:44:32 +000086 return null;
87 }
88
89 /**
90 * Process @bind & @unbind.
91 * @param type : bind or unbind
92 * @return the visitor parsing @bind & @unbind annotations.
93 */
94 private AnnotationVisitor processBind(String type) {
95 return new BindAnnotationParser(m_name, type);
96 }
97
98 /**
99 * Process @validate annotation.
100 * @return null.
101 */
102 private AnnotationVisitor processValidate() {
103 Element cb = new Element("callback", "");
104 cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "validate"));
105 cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
Clement Escoffier046c1b12007-09-27 12:47:53 +0000106 m_collector.getElements().put(cb, null);
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000107 return null;
108 }
109
110 /**
111 * Process @invalidate annotation.
112 * @return null.
113 */
114 private AnnotationVisitor processInvalidate() {
115 Element cb = new Element("callback", "");
116 cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "invalidate"));
117 cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
Clement Escoffier046c1b12007-09-27 12:47:53 +0000118 m_collector.getElements().put(cb, null);
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000119 return null;
120 }
121
122 /**
123 * Process @serviceProperty annotation.
124 * @return the visitor parsing the visited annotation.
125 */
126 private AnnotationVisitor processServiceProperty() {
Clement Escoffier046c1b12007-09-27 12:47:53 +0000127 if (! m_collector.getIds().containsKey("provides")) {
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000128 System.err.println("the component does not provide services, skip ServiceProperty for " + m_name);
129 return null;
Clement Escoffier046c1b12007-09-27 12:47:53 +0000130 } else {
131 Element provides = (Element) m_collector.getIds().get("provides");
132 return new PropertyAnnotationParser(provides, m_name);
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000133 }
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000134 }
135
136 /**
137 * Process @property annotation.
138 * @return the visitor parsing the visited annotation.
139 */
140 private AnnotationVisitor processProperty() {
Clement Escoffier046c1b12007-09-27 12:47:53 +0000141 Element prop = null;
142 if (! m_collector.getIds().containsKey("properties")) {
143 prop = new Element("Properties", "");
144 m_collector.getIds().put("properties", prop);
145 m_collector.getElements().put(prop, null);
146 } else {
147 prop = (Element) m_collector.getIds().get("properties");
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000148 }
Clement Escoffier046c1b12007-09-27 12:47:53 +0000149 return new PropertyAnnotationParser(prop, m_name);
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000150 }
151
152 /**
153 * Parse @bind & @unbind annotations.
154 */
155 private final class BindAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
156
157 /**
158 * Method name.
159 */
160 private String m_name;
161
162 /**
163 * Requirement filter.
164 */
165 private String m_filter;
166
167 /**
168 * Is the requirement optional?
169 */
170 private String m_optional;
171
172 /**
173 * Is the requirement aggregate?
174 */
175 private String m_aggregate;
176
177 /**
178 * Required specification.
179 */
180 private String m_specification;
181
182 /**
183 * Requirement id.
184 */
185 private String m_id;
186
187 /**
188 * Bind or Unbind method?
189 */
190 private String m_type;
Clement Escoffiercf88c872008-04-25 16:46:36 +0000191
192 /**
193 * Binding policy.
194 */
195 private String m_policy;
Clement Escoffier83db4a02008-04-29 22:30:56 +0000196
197 /**
198 * Comparator.
199 */
200 private String m_comparator;
Clement Escoffier69cb62d2008-08-01 12:52:36 +0000201
202 /**
203 * From attribute.
204 */
205 private String m_from;
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000206
207 /**
208 * Constructor.
209 * @param bind : method name.
210 * @param type : is the callback a bind or an unbind method.
211 */
212 private BindAnnotationParser(String bind, String type) {
213 m_name = bind;
214 m_type = type;
215 }
216
217 /**
218 * Visit annotation attribute.
219 * @param arg0 : annotation name
220 * @param arg1 : annotation value
221 * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
222 */
223 public void visit(String arg0, Object arg1) {
224 if (arg0.equals("filter")) {
225 m_filter = arg1.toString();
226 return;
227 }
228 if (arg0.equals("optional")) {
229 m_optional = arg1.toString();
230 return;
231 }
232 if (arg0.equals("aggregate")) {
233 m_aggregate = arg1.toString();
234 return;
235 }
236 if (arg0.equals("specification")) {
237 m_specification = arg1.toString();
238 return;
239 }
Clement Escoffiercf88c872008-04-25 16:46:36 +0000240 if (arg0.equals("policy")) {
241 m_policy = arg1.toString();
242 return;
243 }
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000244 if (arg0.equals("id")) {
245 m_id = arg1.toString();
246 return;
247 }
Clement Escoffier83db4a02008-04-29 22:30:56 +0000248 if (arg0.equals("comparator")) {
249 Type type = Type.getType(arg1.toString());
250 m_comparator = type.getClassName();
251 return;
252 }
Clement Escoffier69cb62d2008-08-01 12:52:36 +0000253 if (arg0.equals("from")) {
254 m_from = arg1.toString();
255 return;
256 }
Clement Escoffier83db4a02008-04-29 22:30:56 +0000257
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000258 }
259
260 /**
261 * End of the visit.
262 * Create or append the requirement info to a created or already existing "requires" element.
263 * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
264 */
265 public void visitEnd() {
266 if (m_id == null) {
267 if (m_name.startsWith("bind")) {
268 m_id = m_name.substring("bind".length());
269 } else if (m_name.startsWith("unbind")) {
270 m_id = m_name.substring("unbind".length());
271 } else {
272 System.err.println("Cannot determine the id of the bind method : " + m_name);
273 return;
274 }
275 }
276 // Check if it is a full-determined requirement
Clement Escoffier046c1b12007-09-27 12:47:53 +0000277 Element req = (Element) m_collector.getIds().get(m_id);
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000278 if (req == null) {
279 // Add the complete requires
280 req = new Element("requires", "");
281 if (m_specification != null) {
Clement Escoffierc332fd12008-09-15 12:53:29 +0000282 req.addAttribute(new Attribute("specification", m_specification));
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000283 }
284 if (m_aggregate != null) {
285 req.addAttribute(new Attribute("aggregate", m_aggregate));
286 }
287 if (m_filter != null) {
288 req.addAttribute(new Attribute("filter", m_filter));
289 }
290 if (m_optional != null) {
291 req.addAttribute(new Attribute("optional", m_optional));
292 }
Clement Escoffiercf88c872008-04-25 16:46:36 +0000293 if (m_policy != null) {
294 req.addAttribute(new Attribute("policy", m_policy));
295 }
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000296 if (m_id != null) {
297 req.addAttribute(new Attribute("id", m_id));
298 }
Clement Escoffier83db4a02008-04-29 22:30:56 +0000299 if (m_comparator != null) {
300 req.addAttribute(new Attribute("comparator", m_comparator));
301 }
Clement Escoffier69cb62d2008-08-01 12:52:36 +0000302 if (m_from != null) {
303 req.addAttribute(new Attribute("from", m_from));
304 }
Clement Escoffier83db4a02008-04-29 22:30:56 +0000305 } else {
Clement Escoffierc332fd12008-09-15 12:53:29 +0000306 String itf = req.getAttribute("specification");
Clement Escoffier83db4a02008-04-29 22:30:56 +0000307 String aggregate = req.getAttribute("aggregate");
308 String optional = req.getAttribute("optional");
309 String filter = req.getAttribute("filter");
310 String policy = req.getAttribute("policy");
311 String comparator = req.getAttribute("comparator");
Clement Escoffier69cb62d2008-08-01 12:52:36 +0000312 String from = req.getAttribute("from");
Clement Escoffier83db4a02008-04-29 22:30:56 +0000313 if (m_specification != null) {
314 if (itf == null) {
Clement Escoffierc332fd12008-09-15 12:53:29 +0000315 req.addAttribute(new Attribute("specification", m_specification));
Clement Escoffier83db4a02008-04-29 22:30:56 +0000316 } else if (! m_specification.equals(itf)) {
317 System.err.println("The required specification is not the same than previouly : " + m_specification + " & " + itf);
318 return;
319 }
320 }
321
322 if (m_optional != null) {
323 if (optional == null) {
324 req.addAttribute(new Attribute("optional", m_optional));
325 } else if (! m_optional.equals(optional)) {
326 System.err.println("The optional attribute is not always the same");
327 return;
328 }
329 }
330
331 if (m_aggregate != null) {
332 if (aggregate == null) {
333 req.addAttribute(new Attribute("aggregate", m_aggregate));
334 } else if (! m_aggregate.equals(aggregate)) {
335 System.err.println("The aggregate attribute is not always the same");
336 return;
337 }
338 }
339
340 if (m_filter != null) {
341 if (filter == null) {
342 req.addAttribute(new Attribute("filter", m_filter));
343 } else if (! m_filter.equals(filter)) {
344 System.err.println("The filter attribute is not always the same");
345 return;
346 }
347 }
348
349 if (m_policy != null) {
350 if (policy == null) {
351 req.addAttribute(new Attribute("policy", m_policy));
352 } else if (! m_policy.equals(policy)) {
353 System.err.println("The policy attribute is not always the same");
354 return;
355 }
356 }
357
358 if (m_comparator != null) {
359 if (comparator == null) {
360 req.addAttribute(new Attribute("comparator", m_comparator));
Clement Escoffier69cb62d2008-08-01 12:52:36 +0000361 } else if (! m_comparator.equals(comparator)) {
Clement Escoffier83db4a02008-04-29 22:30:56 +0000362 System.err.println("The comparator attribute is not always the same");
363 return;
364 }
365 }
366
Clement Escoffier69cb62d2008-08-01 12:52:36 +0000367 if (m_from != null) {
368 if (from == null) {
369 req.addAttribute(new Attribute("from", m_from));
370 } else if (! m_from.equals(from)) {
371 System.err.println("The from attribute is not always the same");
372 return;
373 }
374
375 }
376
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000377 }
378 Element method = new Element("callback", "");
379 method.addAttribute(new Attribute("method", m_name));
380 method.addAttribute(new Attribute("type", m_type));
381 req.addElement(method);
Clement Escoffier046c1b12007-09-27 12:47:53 +0000382 m_collector.getIds().put(m_id, req);
383 m_collector.getElements().put(req, null);
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000384 return;
385 }
386 }
387
388 private final class PropertyAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
389
390 /**
391 * Parent element.
392 */
393 private Element m_parent;
394
395 /**
396 * Attached method.
397 */
398 private String m_method;
399
400 /**
401 * Property name.
402 */
403 private String m_name;
404
405 /**
406 * Property value.
407 */
408 private String m_value;
409
410 /**
411 * Constructor.
412 * @param parent : parent element.
413 * @param method : attached method.
414 */
415 private PropertyAnnotationParser(Element parent, String method) {
416 m_parent = parent;
417 m_method = method;
418 }
419
420 /**
421 * Visit annotation attributes.
422 * @param arg0 : annotation name
423 * @param arg1 : annotation value
424 * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
425 */
426 public void visit(String arg0, Object arg1) {
427 if (arg0.equals("name")) {
428 m_name = arg1.toString();
429 return;
430 }
431 if (arg0.equals("value")) {
432 m_value = arg1.toString();
433 return;
434 }
435 }
436
437 /**
438 * End of the visit.
439 * Append the computed element to the parent element.
440 * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
441 */
442 public void visitEnd() {
443 if (m_name == null && m_method.startsWith("set")) {
444 m_name = m_method.substring("set".length());
445 }
446 Element[] props = m_parent.getElements("Property");
447 Element prop = null;
Clement Escoffierce0e1e52008-03-28 15:33:36 +0000448 for (int i = 0; props != null && prop == null && i < props.length; i++) {
Clement Escoffier1f949342007-10-16 14:04:28 +0000449 String name = props[i].getAttribute("name");
450 if (name != null && name.equals(m_name)) {
Clement Escoffierf5fc5562007-08-14 13:44:32 +0000451 prop = props[i];
452 }
453 }
454
455 if (prop == null) {
456 prop = new Element("property", "");
457 m_parent.addElement(prop);
458 if (m_name != null) {
459 prop.addAttribute(new Attribute("name", m_name));
460 }
461 }
462
463 prop.addAttribute(new Attribute("method", m_method));
464 if (m_value != null) {
465 prop.addAttribute(new Attribute("value", m_value));
466 }
467
468 }
469 }
470}