package fr.imag.adele.apam.declarations.encoding.ipojo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.Vector;
import org.apache.felix.ipojo.parser.FieldMetadata;
import org.apache.felix.ipojo.parser.MethodMetadata;
import org.apache.felix.ipojo.parser.PojoMetadata;
import fr.imag.adele.apam.declarations.instrumentation.InstrumentedClass;
import fr.imag.adele.apam.declarations.instrumentation.LoadedClassMetadata;
/**
* A utility class to obtain information about declared fields and methods.
*
* It tries to use java reflection metadata if available, otherwise it falls backs to use
* the iPojo metadata
*
* @author vega
*
*/
public class InstrumentedClassMetadata implements InstrumentedClass {
/**
* The iPojo generated metadata
*/
private final PojoMetadata pojoMetadata;
/**
* The name of the instrumented class
*/
private final String className;
/**
* The optional reflection information
*/
private final LoadedClassMetadata loadedClass;
public InstrumentedClassMetadata(String className, PojoMetadata pojoMetadata, Class<?> instrumentedCode) {
this.className = className;
this.pojoMetadata = pojoMetadata;
this.loadedClass = instrumentedCode != null ? new LoadedClassMetadata(instrumentedCode) : null;
}
/**
* The list of supported collections for aggregate dependencies
*/
private final static Class<?>[] supportedCollections = new Class<?>[] { Collection.class, List.class, Vector.class, Set.class };
/**
* The list of supported types for push message queues
*/
private final static Class<?>[] supportedMessageQueues = new Class<?>[] { Queue.class, };
/**
* Utility method to get the associated box class name for a primitive type
*/
private final static Map<String, Class<?>> box = new HashMap<String, Class<?>>();
static {
box.put(Boolean.TYPE.getName(), Boolean.class);
box.put(Character.TYPE.getName(), Character.class);
box.put(Byte.TYPE.getName(), Byte.class);
box.put(Short.TYPE.getName(), Short.class);
box.put(Integer.TYPE.getName(), Integer.class);
box.put(Float.TYPE.getName(), Float.class);
box.put(Long.TYPE.getName(), Long.class);
box.put(Double.TYPE.getName(), Double.class);
}
/**
* If the type of the specified field is one of the supported collections returns the type of the elements
* in the collection, otherwise return null.
*
* May return {@link UNKNOWN_TYPE} if the type of the elements in the collection cannot be determined.
*/
private static String getCollectionType(FieldMetadata field) {
String fieldType = field.getFieldType();
if (fieldType.endsWith("[]")) {
int index = fieldType.indexOf('[');
return boxed(fieldType.substring(0, index));
}
for (Class<?> supportedCollection : supportedCollections) {
if (supportedCollection.getCanonicalName().equals(fieldType)) {
return UNKNOWN_TYPE;
}
}
return null;
}
private static String getMessageType(FieldMetadata field) {
String fieldType = field.getFieldType();
for (Class<?> supportedMessage : supportedMessageQueues) {
if (supportedMessage.getCanonicalName().equals(fieldType)) {
return UNKNOWN_TYPE;
}
}
return null;
}
private static String boxed(String type) {
Class<?> boxed = box.get(type);
return boxed != null ? boxed.getCanonicalName() : type;
}
@Override
public String getName() {
return className;
}
@Override
public String getDeclaredFieldType(String fieldName) throws NoSuchFieldException {
/*
* Try to get reflection information if available,.
*/
String result = null;
if (loadedClass != null) {
try {
result = loadedClass.getDeclaredFieldType(fieldName);
} catch (Exception e) {
}
}
if (result != null) {
return result;
}
/*
* Get iPojo metadata
*/
FieldMetadata fieldIPojoMetadata = null;
if ((pojoMetadata != null) && (pojoMetadata.getField(fieldName) != null)) {
fieldIPojoMetadata = pojoMetadata.getField(fieldName);
}
if (fieldIPojoMetadata != null) {
return fieldIPojoMetadata.getFieldType();
}
throw new NoSuchFieldException("unavailable field " + fieldName);
}
@Override
public String getFieldType(String fieldName) throws NoSuchFieldException {
/*
* Try to get reflection information if available,.
*/
String result = null;
if (loadedClass != null) {
try {
result = loadedClass.getFieldType(fieldName);
} catch (Exception e) {
}
}
if (result != null) {
return result;
}
/*
* Get iPojo metadata
*/
FieldMetadata fieldIPojoMetadata = null;
if ((pojoMetadata != null) && (pojoMetadata.getField(fieldName) != null)) {
fieldIPojoMetadata = pojoMetadata.getField(fieldName);
}
if (fieldIPojoMetadata != null) {
/*
* Verify if it is a collection
*/
String collectionType = getCollectionType(fieldIPojoMetadata);
if (collectionType != null) {
return collectionType;
}
/*
* Verify if it is a message
*/
String messageType = getMessageType(fieldIPojoMetadata);
if (messageType != null) {
return messageType;
}
/*
* Otherwise we just return the raw type
*/
return fieldIPojoMetadata.getFieldType();
}
throw new NoSuchFieldException("unavailable field " + fieldName);
}
@Override
public int getMethodParameterNumber(String methodName, boolean includeInherited) throws NoSuchMethodException {
/*
* Try to get reflection information if available,.
*/
if (loadedClass != null) {
try {
return loadedClass.getMethodParameterNumber(methodName,includeInherited);
} catch (Exception e) {
}
}
/*
* Try to use iPojo metadata
*/
if (pojoMetadata != null) {
for (MethodMetadata method : pojoMetadata.getMethods(methodName)) {
return method.getMethodArguments().length;
}
}
throw new NoSuchMethodException("unavailable metadata for method " + methodName);
}
@Override
public String getMethodParameterType(String methodName, boolean includeInherited) throws NoSuchMethodException {
/*
* Try to get reflection information if available,.
*/
String result = null;
if (loadedClass != null) {
try {
result = loadedClass.getMethodParameterType(methodName,includeInherited);
} catch (Exception e) {
}
}
if (result != null) {
return result;
}
/*
* Try to use iPojo metadata
*/
MethodMetadata methodIPojoMetadata = null;
if (pojoMetadata != null) {
for (MethodMetadata method : pojoMetadata.getMethods(methodName)) {
String arguments[] = method.getMethodArguments();
boolean match = (1 == arguments.length);
if (match) {
methodIPojoMetadata = method;
}
}
}
if (methodIPojoMetadata != null) {
return boxed(methodIPojoMetadata.getMethodArguments()[0]);
}
throw new NoSuchMethodException("unavailable metadata for method " + methodName);
}
@Override
public String[] getMethodParameterTypes(String methodName, boolean includeInherited) throws NoSuchMethodException {
/*
* Try to get reflection information if available,.
*/
String[] result = null;
if (loadedClass != null) {
try {
result = loadedClass.getMethodParameterTypes(methodName,includeInherited);
} catch (Exception e) {
}
}
if (result != null) {
return result;
}
/*
* Try to use iPojo metadata
*/
List<String> signature = new ArrayList<String>();
if (pojoMetadata != null) {
for (MethodMetadata method : pojoMetadata.getMethods(methodName)) {
for (String argument : method.getMethodArguments()) {
signature.add(boxed(argument));
}
return signature.toArray(new String[0]);
}
}
throw new NoSuchMethodException("unavailable metadata for method " + methodName);
}
@Override
public String getMethodReturnType(String methodName, String methodSignature, boolean includeInherited) throws NoSuchMethodException {
/*
* Try to get reflection information if available,.
*/
String result = null;
if (loadedClass != null) {
try {
result = loadedClass.getMethodReturnType(methodName,methodSignature,includeInherited);
} catch (Exception e) {
}
}
if (result != null) {
return result;
}
/*
* Try to use iPojo metadata
*/
MethodMetadata methodIPojoMetadata = null;
if (pojoMetadata != null) {
for (MethodMetadata method : pojoMetadata.getMethods(methodName)) {
if (methodSignature == null) {
methodIPojoMetadata = method;
break;
}
String signature[] = methodSignature.split(",");
String arguments[] = method.getMethodArguments();
boolean match = (signature.length == arguments.length);
for (int i = 0; match && i < signature.length; i++) {
if (!signature[i].equals(arguments[i])) {
match = false;
}
}
if (match) {
methodIPojoMetadata = method;
break;
}
}
}
if (methodIPojoMetadata != null) {
return boxed(methodIPojoMetadata.getMethodReturn());
}
throw new NoSuchMethodException("unavailable metadata for method " + methodName + "(" + methodSignature != null ? methodSignature : "" + ")");
}
@Override
public boolean isCollectionField(String fieldName) throws NoSuchFieldException {
/*
* Try to get reflection information if available,.
*/
if (loadedClass != null) {
try {
return loadedClass.isCollectionField(fieldName);
} catch (Exception e) {
}
}
/*
* Get iPojo metadata
*/
FieldMetadata fieldIPojoMetadata = null;
if ((pojoMetadata != null) && (pojoMetadata.getField(fieldName) != null)) {
fieldIPojoMetadata = pojoMetadata.getField(fieldName);
}
if (fieldIPojoMetadata != null) {
return getCollectionType(fieldIPojoMetadata) != null;
}
throw new NoSuchFieldException("unavailable metadata for field " + fieldName);
}
@Override
public boolean isMessageQueueField(String fieldName) throws NoSuchFieldException {
/*
* Try to get reflection information if available,.
*/
if (loadedClass != null) {
try {
return loadedClass.isMessageQueueField(fieldName);
} catch (Exception e) {
}
}
/*
* Get iPojo metadata
*/
FieldMetadata fieldIPojoMetadata = null;
if ((pojoMetadata != null) && (pojoMetadata.getField(fieldName) != null)) {
fieldIPojoMetadata = pojoMetadata.getField(fieldName);
}
if (fieldIPojoMetadata != null) {
return getMessageType(fieldIPojoMetadata) != null;
}
throw new NoSuchFieldException("unavailable metadata for field " + fieldName);
}
}