/**
* Copyright 2005-2016 Red Hat, Inc.
*
* Red Hat 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 io.fabric8.jolokia.support;
import org.jolokia.client.J4pClient;
import org.jolokia.client.exception.J4pException;
import org.jolokia.client.request.AbtractJ4pMBeanRequest;
import org.jolokia.client.request.J4pExecRequest;
import org.jolokia.client.request.J4pReadRequest;
import org.jolokia.client.request.J4pResponse;
import org.jolokia.client.request.J4pWriteRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.ObjectName;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
public class JolokiaInvocationHandler implements InvocationHandler {
private static final transient Logger LOG = LoggerFactory.getLogger(JolokiaInvocationHandler.class);
private final J4pClient jolokia;
private final ObjectName objectName;
private final Class<?> interfaceClass;
public static <T> T newProxyInstance(J4pClient jolokia, ObjectName objectName, Class<T> interfaceClass) {
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass}, new JolokiaInvocationHandler(jolokia, objectName, interfaceClass));
}
public JolokiaInvocationHandler(J4pClient jolokia, ObjectName objectName, Class<?> interfaceClass) {
this.jolokia = jolokia;
this.objectName = objectName;
this.interfaceClass = interfaceClass;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
String attribute;
AbtractJ4pMBeanRequest request;
if ((attribute = getterAttributeName(method)) != null) {
request = new J4pReadRequest(objectName, attribute);
} else if ((attribute = setterAttributeName(method)) != null) {
request = new J4pWriteRequest(objectName, attribute, args[0]);
} else {
name = executeMethodName(method);
if (args == null | method.getParameterTypes().length == 0) {
request = new J4pExecRequest(objectName, name);
} else {
request = new J4pExecRequest(objectName, name, args);
}
}
try {
request.setPreferredHttpMethod("POST");
J4pResponse response = jolokia.execute(request);
Object value = response.getValue();
return JolokiaHelpers.convertJolokiaToJavaType(method.getReturnType(), value);
} catch (J4pException e) {
List<Object> argsList = args == null ? null : Arrays.asList(args);
LOG.warn("Failed to invoke " + objectName + " method: " + name + " with arguments: " + argsList + ". " + e, e);
throw e;
}
}
protected String getterAttributeName(Method method) {
String name = method.getName();
int length = name.length();
Class<?>[] parameterTypes = method.getParameterTypes();
Class<?> returnType = method.getReturnType();
if (parameterTypes.length == 0 && !Void.class.equals(returnType)) {
boolean returnsBool = returnType.equals(Boolean.class) || returnType.equals(boolean.class);
if (name.startsWith("get") && length > 3) {
return name.substring(3);
} else if (returnsBool && name.startsWith("is") && length > 2) {
return name.substring(2);
}
}
return null;
}
protected String setterAttributeName(Method method) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
String name = method.getName();
int nameLength = name.length();
if (name.startsWith("set") && nameLength > 3) {
return name.substring(3);
}
}
return null;
}
/**
* Returns the method name with parameter types if there is more than one method with the same name on the interface class
*/
protected String executeMethodName(Method method) {
String name = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
if (methodCount(interfaceClass, name) > 1) {
StringBuilder buffer = new StringBuilder(name);
buffer.append("(");
boolean first = true;
for (Class<?> parameterType : parameterTypes) {
if (first) {
first = false;
} else {
buffer.append(",");
}
buffer.append(parameterType.getCanonicalName());
}
buffer.append(")");
return buffer.toString();
}
return name;
}
/**
* Returns the number of declared methods on the given clazz
*/
protected static int methodCount(Class<?> clazz, String name) {
int answer = 0;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
if (name.equals(method.getName())) {
answer++;
}
}
if (!clazz.equals(Object.class)) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && !superclass.equals(Object.class)) {
answer += methodCount(superclass, name);
}
}
return answer;
}
}