blob: aafd81f04fcffeef56092a97fde7a07ca712ddb4 [file] [log] [blame]
/*
* 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 + "}"));
}
}
}
}