New annotation processor. The manipulator manages custom annotations (provided by external handlers).
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@579994 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Attribute.java b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Attribute.java
deleted file mode 100644
index 482f693..0000000
--- a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Attribute.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.ipojo.annotations;
-
-/**
-* This annotation declares an attribute.
-* This annotation must only be used in the attributes array of the Element annotation.
-* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
-*/
-public @interface Attribute {
-
- /**
- * Set attribute name.
- */
- String name();
-
- /**
- * Set attribute value.
- */
- String value();
-
-}
diff --git a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java
index e449cd4..e4bfaeb 100644
--- a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java
+++ b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Controller.java
@@ -28,6 +28,5 @@
@Target(ElementType.FIELD)
public @interface Controller {
-
}
diff --git a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Element.java b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Element.java
deleted file mode 100644
index 904d5b9..0000000
--- a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Element.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.ipojo.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Target;
-
-/**
-* This annotation declares a generic element.
-* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
-*/
-@Target(ElementType.TYPE)
-public @interface Element {
-
- /**
- * Set element name.
- */
- String name();
-
- /**
- * Set the element namespace.
- * Default : no namespace.
- */
- String namespace() default "";
-
- /**
- * Set element attributes (@Attribute).
- * Default : no attributes.
- */
- Attribute[] attributes() default { };
-
- /**
- * Set element sub-elements (@SubElement).
- * Default : no sub-element.
- */
- SubElement[] elements() default { };
-
-}
diff --git a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
index 3ea29b6..1b25d05 100644
--- a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
+++ b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/Provides.java
@@ -32,7 +32,7 @@
* Set the provided specifications.
* Default : all implemented interfaces
*/
- String specification() default "";
+ Class[] specifications() default { };
/**
* Set the service object creation policy.
diff --git a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/SubElement.java b/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/SubElement.java
deleted file mode 100644
index a0d3179..0000000
--- a/ipojo/annotations/src/main/java/org/apache/felix/ipojo/annotations/SubElement.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.felix.ipojo.annotations;
-
-/**
-* This annotation declares a sub-attribute.
-* This annotation must only be used in the elements array of the Element annotation.
-* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
-*/
-public @interface SubElement {
-
- /**
- * Set the sub-element name.
- */
- String name();
-
- /**
- * Set the sub-element namespace.
- * Default : no namespace.
- */
- String namespace() default "";
-
- /**
- * Set the sub-element attributes (@Attribute).
- * Default : no attributes.
- */
- Attribute[] attributes() default { };
-
-}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
new file mode 100644
index 0000000..d4534c4
--- /dev/null
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/CustomAnnotationVisitor.java
@@ -0,0 +1,237 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.manipulation.annotations;
+
+import java.lang.reflect.Array;
+
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+/**
+ * Collect metadata from custom annotation.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class CustomAnnotationVisitor extends EmptyVisitor implements AnnotationVisitor {
+
+ /**
+ * PArent element.
+ */
+ private Element m_elem;
+
+ /**
+ * Id attribute (if found).
+ */
+ private String m_id;
+
+ /**
+ * Parent attribute (if found).
+ */
+ private String m_parent;
+
+ /**
+ * Is the custom annotation a first-order annotation.
+ */
+ private boolean m_root;
+
+ /**
+ * MEtadata collector.
+ */
+ private MetadataCollector m_collector;
+
+ /**
+ * Constructor.
+ * @param elem : parent element
+ * @param collector : metadata collector
+ * @param root : is the annotation a root
+ */
+ public CustomAnnotationVisitor(Element elem, MetadataCollector collector, boolean root) {
+ m_elem = elem;
+ m_root = root;
+ m_collector = collector;
+ }
+
+ /**
+ * Check if the given annotation descriptor is an iPOJO custom annotation.
+ * A valid iPOJO custom annotation must contains 'ipojo' or 'handler' in its qualified name.
+ * @param desc : annotation descriptor
+ * @return : true if the given descriptor is an iPOJO custom annotation
+ */
+ public static boolean isCustomAnnotation(String desc) {
+ desc = desc.toLowerCase();
+ if (desc.indexOf("ipojo") != -1 || desc.indexOf("handler") != -1) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Build the element object from the given descriptor.
+ * @param desc : annotation descriptor
+ * @return : the element
+ */
+ public static Element buildElement(String desc) {
+ String s = (desc.replace('/', '.')).substring(1, desc.length() - 1);
+ int index = s.lastIndexOf('.');
+ String name = s.substring(index + 1);
+ String namespace = s.substring(0, index);
+ return new Element(name, namespace);
+ }
+
+ /**
+ * Visit an 'simple' annotation attribute.
+ * This method is used for primitive arrays too.
+ * @param arg0 : attribute name
+ * @param arg1 : attribute value
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ if (arg1.getClass().isArray()) {
+ // Primitive arrays case
+ String v = null;
+ int index = Array.getLength(arg1);
+ for (int i = 0; i < index; i++) {
+ if (v == null) {
+ v = "{" + Array.get(arg1, i);
+ } else {
+ v += "," + Array.get(arg1, i);
+ }
+ }
+ v += "}";
+ m_elem.addAttribute(new Attribute(arg0, v));
+ return;
+ }
+ // Attributes are added as normal attributes
+ m_elem.addAttribute(new Attribute(arg0, arg1.toString()));
+ if (m_root) {
+ if (arg0.equals("id")) {
+ m_id = arg1.toString();
+ } else if (arg0.equals("parent")) {
+ m_parent = arg1.toString();
+ }
+ }
+ }
+
+ /**
+ * Visit a sub-annotation.
+ * @param arg0 : attribute name.
+ * @param arg1 : annotation description
+ * @return an annotation visitor which will visit the given annotation
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, java.lang.String)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ // Sub annotations are mapped to sub-elements
+ Element elem = buildElement(arg1);
+ m_elem.addElement(elem);
+ return new CustomAnnotationVisitor(elem, m_collector, false);
+ }
+
+ /**
+ * Visit an array attribute.
+ * @param arg0 : attribute name
+ * @return a visitor which will visit each element of the array
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitArray(java.lang.String)
+ */
+ public AnnotationVisitor visitArray(String arg0) {
+ return new SubArrayVisitor(m_elem, arg0);
+ }
+
+ /**
+ * End of the visit.
+ * All attribute was visited, we can update collectors data.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_root) {
+ if (m_id != null) {
+ m_collector.getIds().put(m_id, m_elem);
+ }
+ m_collector.getElements().put(m_elem, m_parent);
+ }
+ }
+
+ private class SubArrayVisitor extends EmptyVisitor implements AnnotationVisitor {
+ /**
+ * Parent element.
+ */
+ private Element m_elem;
+
+ /**
+ * Attribute name.
+ */
+ private String m_name;
+
+ /**
+ * Attribute value.
+ * (accumulator)
+ */
+ private String m_acc;
+
+ /**
+ * Constructor.
+ * @param elem : parent element.
+ * @param name : attribute name.
+ */
+ public SubArrayVisitor(Element elem, String name) {
+ m_elem = elem;
+ m_name = name;
+ }
+
+ /**
+ * Visit a 'simple' element of the visited array.
+ * @param arg0 : null
+ * @param arg1 : element value.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ if (m_acc == null) {
+ m_acc = "{" + arg1.toString();
+ } else {
+ m_acc = m_acc + "," + arg1.toString();
+ }
+ }
+
+ /**
+ * Visit an annotation element of the visited array.
+ * @param arg0 : null
+ * @param arg1 : annotation to visit
+ * @return the visitor which will visit the annotation
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitAnnotation(java.lang.String, java.lang.String)
+ */
+ public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
+ // Sub annotations are map to sub-elements
+ Element elem = buildElement(arg1);
+ m_elem.addElement(elem);
+ return new CustomAnnotationVisitor(elem, m_collector, false);
+ }
+
+ /**
+ * End of the visit.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ if (m_acc != null) {
+ // We have analyzed an attribute
+ m_elem.addAttribute(new Attribute(m_name, m_acc + "}"));
+ }
+ }
+
+ }
+}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java
index 4ecdc26..f6ecd63 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/FieldCollector.java
@@ -33,7 +33,7 @@
/**
* Collected element.
*/
- private Element m_element;
+ private MetadataCollector m_collector;
/**
* Field name.
@@ -43,10 +43,10 @@
/**
* Constructor.
* @param fieldName : field name
- * @param elem : element on which append the collected metadata.
+ * @param collector : metadata collector.
*/
- public FieldCollector(String fieldName, Element elem) {
- m_element = elem;
+ public FieldCollector(String fieldName, MetadataCollector collector) {
+ m_collector = collector;
m_field = fieldName;
}
@@ -61,23 +61,41 @@
if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Requires;")) {
return new RequiresAnnotationParser(m_field);
}
+ if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Controller;")) {
+ Element elem = new Element("controller", "");
+ elem.addAttribute(new Attribute("field", m_field));
+ m_collector.getElements().put(elem, null);
+ return null;
+ }
if (arg0.equals("Lorg/apache/felix/ipojo/annotations/ServiceProperty;")) {
- if (m_element.getElements("Provides", "").length == 0) {
+ if (! m_collector.getIds().containsKey("provides")) { // The provides annotation is already computed.
System.err.println("The component does not provide services, skip ServiceProperty for " + m_field);
return null;
+ } else {
+ // Get the provides element
+ Element parent = (Element) m_collector.getIds().get("provides");
+ return new PropertyAnnotationParser(m_field, parent);
}
- Element provides = m_element.getElements("Provides", "")[0];
- return new PropertyAnnotationParser(provides, m_field);
+
}
if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Property;")) {
Element parent = null;
- if (m_element.getElements("Properties", "").length == 0) {
+ if (! m_collector.getIds().containsKey("properties")) {
parent = new Element("Properties", "");
- m_element.addElement(parent);
+ m_collector.getIds().put("properties", parent);
+ m_collector.getElements().put(parent, null);
+ } else {
+ parent = (Element) m_collector.getIds().get("properties");
}
- parent = m_element.getElements("Properties", "")[0];
- return new PropertyAnnotationParser(parent, m_field);
+ return new PropertyAnnotationParser(m_field, parent);
}
+
+ if (CustomAnnotationVisitor.isCustomAnnotation(arg0)) {
+ Element elem = CustomAnnotationVisitor.buildElement(arg0);
+ elem.addAttribute(new Attribute("field", m_field)); // Add a field attribute
+ return new CustomAnnotationVisitor(elem, m_collector, true);
+ }
+
return null;
}
@@ -155,20 +173,18 @@
* Create a "requires" element
* @see org.objectweb.asm.AnnotationVisitor#visitEnd()
*/
- public void visitEnd() {
- // Check if it is a full-determined requirement
+ public void visitEnd() {
Element req = null;
- Element[] reqs = m_element.getElements("requires");
- for (int i = 0; i < reqs.length; i++) {
- if (reqs[i].containsAttribute("id") && (reqs[i].getAttribute("id").equals(m_id) || reqs[i].getAttribute("id").equals(m_field))) {
- req = reqs[i];
- break;
- }
+ if (m_id == null) {
+ req = (Element) m_collector.getIds().get(m_field);
+ } else {
+ req = (Element) m_collector.getIds().get(m_id);
}
+
if (req == null) {
- // Add the complete requires
req = new Element("requires", "");
}
+
req.addAttribute(new Attribute("field", m_field));
if (m_specification != null) {
req.addAttribute(new Attribute("interface", m_specification));
@@ -185,7 +201,15 @@
if (m_id != null) {
req.addAttribute(new Attribute("id", m_id));
}
- m_element.addElement(req);
+
+ if (m_id != null) {
+ m_collector.getIds().put(m_id, req);
+ } else {
+ m_collector.getIds().put(m_field, req);
+ }
+
+ m_collector.getElements().put(req, null);
+
return;
}
}
@@ -196,7 +220,7 @@
private final class PropertyAnnotationParser extends EmptyVisitor implements AnnotationVisitor {
/**
- * Parent element (element on which append collected metadata).
+ * Parent element element.
*/
private Element m_parent;
@@ -221,7 +245,7 @@
* @param parent : parent element.
* @param field : field name.
*/
- private PropertyAnnotationParser(Element parent, String field) {
+ private PropertyAnnotationParser(String field, Element parent) {
m_parent = parent;
m_field = field;
}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
index c091cb1..e2ed9ea 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MetadataCollector.java
@@ -18,12 +18,18 @@
*/
package org.apache.felix.ipojo.manipulation.annotations;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
import org.apache.felix.ipojo.metadata.Attribute;
import org.apache.felix.ipojo.metadata.Element;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
import org.objectweb.asm.commons.EmptyVisitor;
/**
@@ -48,6 +54,19 @@
*/
private boolean m_containsAnnotation = false;
+ /**
+ * Map of [element ids, element].
+ * This map is used to easily get an already created element.
+ */
+ private Map m_ids = new HashMap();
+
+ /**
+ * Map of [element, referto].
+ * This map is used to recreate the element hierarchie.
+ * Stored element are added under referred element.
+ */
+ private Map m_elements = new HashMap();
+
public Element getElem() {
return m_elem;
}
@@ -55,6 +74,7 @@
public boolean isAnnotated() {
return m_containsAnnotation;
}
+
/**
* Start visiting a class.
@@ -68,6 +88,8 @@
* @see org.objectweb.asm.ClassAdapter#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
*/
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ m_ids = new HashMap();
+ m_elements = new HashMap();
m_className = name;
}
@@ -94,13 +116,15 @@
return new ProvidesVisitor();
}
- //@Element
- if (desc.equals("Lorg/apache/felix/ipojo/annotations/Element;")) {
- return new ElementVisitor(m_elem);
+ if (CustomAnnotationVisitor.isCustomAnnotation(desc)) {
+ Element elem = CustomAnnotationVisitor.buildElement(desc);
+ return new CustomAnnotationVisitor(elem, this, true);
}
return null;
}
+
+
/**
* Visit a field.
@@ -114,7 +138,7 @@
* @see org.objectweb.asm.ClassAdapter#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
*/
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
- return new FieldCollector(name, m_elem);
+ return new FieldCollector(name, this);
}
/**
@@ -129,10 +153,42 @@
* @see org.objectweb.asm.ClassAdapter#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
*/
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
- return new MethodCollector(name, m_elem);
+ return new MethodCollector(name, this);
}
/**
+ * End of the visit : compute final elements.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ // Recompute the tree
+ Set elems = getElements().keySet();
+ Iterator it = elems.iterator();
+ while (it.hasNext()) {
+ Element current = (Element) it.next();
+ String reference = (String) getElements().get(current);
+ if (reference == null) {
+ m_elem.addElement(current);
+ } else {
+ Element ref = (Element) getIds().get(reference);
+ if (ref == null) {
+ System.err.println("The element " + reference + " is not declared - skip the element " + current.toXMLString());
+ } else {
+ ref.addElement(current);
+ }
+ }
+ }
+ }
+
+ protected Map getIds() {
+ return m_ids;
+ }
+
+ protected Map getElements() {
+ return m_elements;
+ }
+
+ /**
* Parse the @provides annotation.
*/
private class ProvidesVisitor extends EmptyVisitor implements AnnotationVisitor {
@@ -148,21 +204,64 @@
* @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
*/
public void visit(String arg0, Object arg1) {
- if (arg0.equals("specifications")) {
- m_prov.addAttribute(new Attribute("interface", arg1.toString()));
- }
if (arg0.equals("factory")) {
m_prov.addAttribute(new Attribute("factory", arg1.toString()));
}
}
/**
+ * Visit specifications array.
+ * @param arg0 : attribute name
+ * @return a visitor visiting each element of the array.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitArray(java.lang.String)
+ */
+ public AnnotationVisitor visitArray(String arg0) {
+ if (arg0.equals("specifications")) {
+ return new InterfaceArrayVisitor();
+ } else {
+ return null;
+ }
+ }
+
+ /**
* End of the visit.
* Append to the parent element the computed "provides" element.
* @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
*/
public void visitEnd() {
- m_elem.addElement(m_prov);
+ getIds().put("provides", m_prov);
+ getElements().put(m_prov, null);
+ }
+
+ private class InterfaceArrayVisitor extends EmptyVisitor {
+ /**
+ * List of parsed interface.
+ */
+ private String m_itfs;
+
+ /**
+ * Visit one element of the array.
+ * @param arg0 : null
+ * @param arg1 : element value.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
+ */
+ public void visit(String arg0, Object arg1) {
+ if (m_itfs == null) {
+ m_itfs = "{" + ((Type) arg1).getClassName();
+ } else {
+ m_itfs += "," + ((Type) arg1).getClassName();
+ }
+ }
+
+ /**
+ * End of the array visit.
+ * Add the attribute to 'provides' element.
+ * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
+ */
+ public void visitEnd() {
+ m_prov.addAttribute(new Attribute("interface", m_itfs + "}"));
+ }
+
}
}
@@ -250,164 +349,9 @@
if (m_propagation != null) {
Element props = new Element("properties", "");
props.addAttribute(new Attribute("propagation", m_propagation));
- m_elem.addElement(props);
+ getIds().put("properties", props);
+ getElements().put(props, null);
}
}
}
-
- /**
- * Parse the @Element & @SubElement annotations.
- */
- private class ElementVisitor extends EmptyVisitor implements AnnotationVisitor {
-
- /**
- * Element name.
- */
- private String m_name;
-
- /**
- * Element namespace.
- */
- private String m_namespace;
-
- /**
- * Parent Element.
- */
- private Element m_parent;
-
- /**
- * Accumulator element to store temporary attributes and sub-elements.
- */
- private Element m_accu = new Element("accu", "");
-
- /**
- * Constructor.
- * @param parent : parent element.
- */
- public ElementVisitor(Element parent) {
- m_parent = parent;
- }
-
- /**
- * Visit annotation attribute.
- * @param arg0 : name of the attribute
- * @param arg1 : value of the attribute
- * @see org.objectweb.asm.AnnotationVisitor#visit(java.lang.String, java.lang.Object)
- */
- public void visit(String arg0, Object arg1) {
- if (arg0.equals("name")) {
- m_name = arg1.toString();
- }
- if (arg0.equals("namespace")) {
- m_namespace = arg1.toString();
- }
- }
-
-
- /**
- * Visit array annotation attribute (attributes & elements).
- * @param arg0 : attribute name
- * @return the annotation visitor which will visit the content of the array
- * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
- */
- public AnnotationVisitor visitArray(String arg0) {
- if (arg0.equals("attributes")) {
- return new EmptyVisitor() {
- public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
- return new AttributeVisitor(m_accu);
- }
-
- };
- }
- if (arg0.equals("elements")) {
- return new EmptyVisitor() {
- public AnnotationVisitor visitAnnotation(String arg0, String arg1) {
- return new ElementVisitor(m_accu);
- }
-
- };
- }
- return null;
- }
-
- /**
- * End of the visit.
- * Append computed element to the parent element.
- * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
- */
- public void visitEnd() {
- Element elem = null;
- if (m_namespace != null) {
- elem = new Element(m_name, m_namespace);
- } else {
- elem = new Element(m_name, "");
- }
-
- Attribute[] atts = m_accu.getAttributes();
- for (int i = 0; i < atts.length; i++) {
- elem.addAttribute(atts[i]);
- }
-
- Element[] elems = m_accu.getElements();
- for (int i = 0; i < elems.length; i++) {
- elem.addElement(elems[i]);
- }
-
- m_parent.addElement(elem);
- }
-
- }
-
- /**
- * Parse an @attribute annotation.
- */
- private class AttributeVisitor extends EmptyVisitor implements AnnotationVisitor {
- /**
- * Parent element.
- */
- private Element m_parent;
-
- /**
- * Attribute name.
- */
- private String m_name;
-
- /**
- * Attribute value.
- */
- private String m_value;
-
- /**
- * Constructor.
- * @param parent : parent element.
- */
- public AttributeVisitor(Element parent) {
- m_parent = parent;
- }
-
- /**
- * Visit attributes.
- * @param arg0 : attribute name
- * @param arg1 : attribute value
- * @see org.objectweb.asm.commons.EmptyVisitor#visit(java.lang.String, java.lang.Object)
- */
- public void visit(String arg0, Object arg1) {
- if (arg0.equals("name")) {
- m_name = arg1.toString();
- return;
- }
- if (arg0.equals("value")) {
- m_value = arg1.toString();
- }
- }
-
- /**
- * End of the visit.
- * Append this current attribute to the parent element.
- * @see org.objectweb.asm.commons.EmptyVisitor#visitEnd()
- */
- public void visitEnd() {
- m_parent.addAttribute(new Attribute(m_name, m_value));
- }
- }
}
diff --git a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
index 582e5e6..2ffa9da 100644
--- a/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
+++ b/ipojo/manipulator/src/main/java/org/apache/felix/ipojo/manipulation/annotations/MethodCollector.java
@@ -30,9 +30,9 @@
public class MethodCollector extends EmptyVisitor {
/**
- * Parent element (component).
+ * Parent collector.
*/
- private Element m_element;
+ private MetadataCollector m_collector;
/**
* Method name.
@@ -42,10 +42,10 @@
/**
* Constructor.
* @param name : name of the method.
- * @param element : parent element.
+ * @param collector : parent collector.
*/
- public MethodCollector(String name, Element element) {
- m_element = element;
+ public MethodCollector(String name, MetadataCollector collector) {
+ m_collector = collector;
m_name = name;
}
@@ -75,6 +75,13 @@
if (arg0.equals("Lorg/apache/felix/ipojo/annotations/Unbind;")) {
return processBind("unbind");
}
+
+ if (CustomAnnotationVisitor.isCustomAnnotation(arg0)) {
+ Element elem = CustomAnnotationVisitor.buildElement(arg0);
+ elem.addAttribute(new Attribute("method", m_name));
+ return new CustomAnnotationVisitor(elem, m_collector, true);
+ }
+
return null;
}
@@ -95,7 +102,7 @@
Element cb = new Element("callback", "");
cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "validate"));
cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
- m_element.addElement(cb);
+ m_collector.getElements().put(cb, null);
return null;
}
@@ -107,7 +114,7 @@
Element cb = new Element("callback", "");
cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("transition", "invalidate"));
cb.addAttribute(new org.apache.felix.ipojo.metadata.Attribute("method", m_name));
- m_element.addElement(cb);
+ m_collector.getElements().put(cb, null);
return null;
}
@@ -116,12 +123,13 @@
* @return the visitor parsing the visited annotation.
*/
private AnnotationVisitor processServiceProperty() {
- if (m_element.getElements("Provides", "").length == 0) {
+ if (! m_collector.getIds().containsKey("provides")) {
System.err.println("the component does not provide services, skip ServiceProperty for " + m_name);
return null;
+ } else {
+ Element provides = (Element) m_collector.getIds().get("provides");
+ return new PropertyAnnotationParser(provides, m_name);
}
- Element provides = m_element.getElements("Provides", "")[0];
- return new PropertyAnnotationParser(provides, m_name);
}
/**
@@ -129,11 +137,15 @@
* @return the visitor parsing the visited annotation.
*/
private AnnotationVisitor processProperty() {
- if (m_element.getElements("Properties", "").length == 0) {
- m_element.addElement(new Element("Properties", ""));
+ Element prop = null;
+ if (! m_collector.getIds().containsKey("properties")) {
+ prop = new Element("Properties", "");
+ m_collector.getIds().put("properties", prop);
+ m_collector.getElements().put(prop, null);
+ } else {
+ prop = (Element) m_collector.getIds().get("properties");
}
- Element props = m_element.getElements("Properties", "")[0];
- return new PropertyAnnotationParser(props, m_name);
+ return new PropertyAnnotationParser(prop, m_name);
}
/**
@@ -232,18 +244,7 @@
}
}
// Check if it is a full-determined requirement
- Element req = null;
- Element[] reqs = m_element.getElements("requires");
- for (int i = 0; i < reqs.length; i++) {
- if (reqs[i].containsAttribute("id") && reqs[i].getAttribute("id").equals(m_id)) {
- req = reqs[i];
- break;
- }
- if (reqs[i].containsAttribute("field") && reqs[i].getAttribute("field").equals(m_id)) {
- req = reqs[i];
- break;
- }
- }
+ Element req = (Element) m_collector.getIds().get(m_id);
if (req == null) {
// Add the complete requires
req = new Element("requires", "");
@@ -267,7 +268,8 @@
method.addAttribute(new Attribute("method", m_name));
method.addAttribute(new Attribute("type", m_type));
req.addElement(method);
- m_element.addElement(req);
+ m_collector.getIds().put(m_id, req);
+ m_collector.getElements().put(req, null);
return;
}
}