/* | |
* 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 { | |
//TODO manage enum annotations. | |
/** | |
* 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 a '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 + "}")); | |
} | |
} | |
} | |
} |