/*
* 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.parser;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.felix.ipojo.InstanceManager;
import org.apache.felix.ipojo.metadata.Element;
import org.objectweb.asm.Type;
/**
* A Method Metadata represents a method from the implementation class.
* This class allows getting information about a method : name, arguments, return type...
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class MethodMetadata {
/**
* Empty Constructor Method Id.
*/
public static final String EMPTY_CONSTRUCTOR_ID = "$init";
/**
* Bundle Context Constructor Method Id.
*/
public static final String BC_CONSTRUCTOR_ID = "$init$org_osgi_framework_BundleContext";
/**
* Constructor Prefix.
*/
public static final String CONSTRUCTOR_PREFIX = "$init";
/**
* The name of the method.
*/
private final String m_name;
/**
* The argument type array.
*/
private final String[] m_arguments;
/**
* The returned type.
*/
private final String m_return;
/**
* The argument names if there were contained in the manifest.
* @since 1.11.0
*/
private final String[] m_names;
/**
* Creates a Method Metadata.
* @param metadata the method manipulation element.
*/
public MethodMetadata(Element metadata) {
m_name = metadata.getAttribute("name");
String arg = metadata.getAttribute("arguments");
String names = metadata.getAttribute("names");
String result = metadata.getAttribute("return");
if (arg != null) {
m_arguments = ParseUtils.parseArrays(arg);
} else {
m_arguments = new String[0];
}
if (names != null) {
m_names = ParseUtils.parseArrays(names);
} else {
m_names = new String[0];
}
if (result != null) {
m_return = result;
} else {
m_return = "void";
}
}
public String getMethodName() {
return m_name;
}
public String[] getMethodArguments() {
return m_arguments;
}
public String[] getMethodArgumentNames() {
return m_names;
}
/**
* Gets the method arguments.
* The keys are the argument names, while the values are the argument type.
* @return the map of argument
* @since 1.10.2
*/
public Map<String, String> getArguments() {
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
for (int i = 0; i < m_names.length; i++) {
map.put(m_names[i], m_arguments[i]);
}
return map;
}
public String getMethodReturn() {
return m_return;
}
/**
* Gets the method unique identifier. For internal usage only.
* A method identifier is a unique string that can be a java field
* that identify the method.
* @return the method identifier.
*/
public String getMethodIdentifier() {
StringBuffer identifier = new StringBuffer(m_name);
for (int i = 0; i < m_arguments.length; i++) {
String arg = m_arguments[i];
if (arg.endsWith("[]")) {
// We have to replace all []
String acc = "";
while (arg.endsWith("[]")) {
arg = arg.substring(0, arg.length() - 2);
acc += "__";
}
identifier.append("$" + arg.replace('.', '_') + acc);
} else {
identifier.append("$" + arg.replace('.', '_'));
}
}
return identifier.toString();
}
/**
* Computes the method id for the given Method object.
* @param method the Method object.
* @return the method id.
*/
public static String computeMethodId(Method method) {
StringBuffer identifier = new StringBuffer(method.getName());
Class[] args = method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
identifier.append('$'); // Argument separator.
if (args[i].isArray()) {
String acc = "__";
if (args[i].getComponentType().isPrimitive()) {
// Primitive array
identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i].getComponentType()));
} else if (args[i].getComponentType().isArray()) {
// Multi-directional array.
Class current = args[i].getComponentType();
while (current.isArray()) {
acc += "__";
current = current.getComponentType();
}
if (current.isPrimitive()) {
acc = FieldMetadata.getPrimitiveTypeByClass(current) + acc;
} else {
acc = current.getName().replace('.', '_') + acc;
}
} else {
// Object array
identifier.append(args[i].getComponentType().getName().replace('.', '_')); // Replace '.' by '_'
}
identifier.append(acc); // Add __ (array)
} else {
if (args[i].isPrimitive()) {
// Primitive type
identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i]));
} else {
// Object type
identifier.append(args[i].getName().replace('.', '_')); // Replace '.' by '_'
}
}
}
return identifier.toString();
}
/**
* Computes the method id for the given Constructor object.
* @param method the Method object.
* @return the method id.
*/
public static String computeMethodId(Constructor method) {
StringBuffer identifier = new StringBuffer("$init");
Class[] args = method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
// If the first argument is the InstanceManager skip it
if (i == 0 && InstanceManager.class.equals(args[i])) {
// Skip it.
continue;
}
identifier.append('$'); // Argument separator.
if (args[i].isArray()) {
String acc = "__";
if (args[i].getComponentType().isPrimitive()) {
// Primitive array
identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i].getComponentType()));
} else if (args[i].getComponentType().isArray()) {
// Multi-directional array.
Class current = args[i].getComponentType();
while (current.isArray()) {
acc += "__";
current = current.getComponentType();
}
} else {
// Object array
identifier.append(args[i].getComponentType().getName().replace('.', '_')); // Replace '.' by '_'
}
identifier.append(acc); // Add __ (array)
} else {
if (args[i].isPrimitive()) {
// Primitive type
identifier.append(FieldMetadata.getPrimitiveTypeByClass(args[i]));
} else {
// Object type
identifier.append(args[i].getName().replace('.', '_')); // Replace '.' by '_'
}
}
}
return identifier.toString();
}
}