/*
* $Id: AbstractEntryPointResolver.java 21939 2011-05-18 13:32:09Z aperepel $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.model.resolvers;
import org.mule.VoidResult;
import org.mule.api.MuleEventContext;
import org.mule.api.model.EntryPointResolver;
import org.mule.api.model.InvocationResult;
import org.mule.api.transformer.TransformerException;
import org.mule.transport.NullPayload;
import org.mule.util.ClassUtils;
import org.mule.util.StringMessageUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A Base class for {@link org.mule.api.model.EntryPointResolver}. It provides parameters for
* detemining if the payload of the message should be transformed first and whether void methods are
* acceptible. It also provides a method cashe for those resolvers that use reflection to discover methods
* on the service.
*/
public abstract class AbstractEntryPointResolver implements EntryPointResolver
{
private static final Log logger = LogFactory.getLog(AbstractEntryPointResolver.class);
private boolean acceptVoidMethods = false;
private boolean synchronizeCall = false;
// @GuardedBy(itself)
private final ConcurrentHashMap methodCache = new ConcurrentHashMap(4);
public boolean isAcceptVoidMethods()
{
return acceptVoidMethods;
}
public void setAcceptVoidMethods(boolean acceptVoidMethods)
{
this.acceptVoidMethods = acceptVoidMethods;
}
protected ConcurrentHashMap getMethodCache(Object component)
{
Class<?> componentClass = component.getClass();
ConcurrentHashMap cache = (ConcurrentHashMap) methodCache.get(componentClass);
if (cache == null)
{
methodCache.putIfAbsent(componentClass, new ConcurrentHashMap(4));
}
return (ConcurrentHashMap) methodCache.get(componentClass);
}
protected Method getMethodByName(Object component, String methodName, MuleEventContext context)
{
return (Method) getMethodCache(component).get(methodName);
}
protected Method addMethodByName(Object component, Method method, MuleEventContext context)
{
Method previousMethod = (Method) getMethodCache(component).putIfAbsent(method.getName(), method);
return (previousMethod != null ? previousMethod : method);
}
protected Method addMethodByArguments(Object component, Method method, Object[] payload)
{
Method previousMethod = (Method) getMethodCache(component).putIfAbsent(getCacheKeyForPayload(component, payload), method);
return (previousMethod != null ? previousMethod : method);
}
protected Method getMethodByArguments(Object component, Object[] payload)
{
Method method = (Method) getMethodCache(component).get(getCacheKeyForPayload(component, payload));
return method;
}
protected String getCacheKeyForPayload(Object component, Object[] payload)
{
StringBuffer key = new StringBuffer(48);
for (int i = 0; i < payload.length; i++)
{
Object o = payload[i];
if (o != null)
{
key.append(o.getClass().getName());
}
else
{
key.append("null");
}
}
key.append(".").append(ClassUtils.getClassName(component.getClass()));
return key.toString();
}
protected Object[] getPayloadFromMessage(MuleEventContext context) throws TransformerException
{
Object temp = context.getMessage().getPayload();
if (temp instanceof Object[])
{
return (Object[]) temp;
}
else if (temp instanceof NullPayload)
{
return ClassUtils.NO_ARGS;
}
else
{
return new Object[]{temp};
}
}
protected InvocationResult invokeMethod(Object component, Method method, Object[] arguments)
throws InvocationTargetException, IllegalAccessException
{
String methodCall = null;
if (logger.isDebugEnabled())
{
methodCall = component.getClass().getName() + "." + method.getName() + "("
+ StringMessageUtils.toString(ClassUtils.getClassTypes(arguments)) + ")";
logger.debug("Invoking " + methodCall);
}
Object result;
if(isSynchronizeCall())
{
synchronized (component)
{
result = method.invoke(component, arguments);
}
}
else
{
result = method.invoke(component, arguments);
}
if (method.getReturnType().equals(Void.TYPE))
{
result = VoidResult.getInstance();
}
if (logger.isDebugEnabled())
{
logger.debug("Result of call " + methodCall + " is " + (result == null ? "null" : "not null"));
}
return new InvocationResult(this, result, method);
}
public boolean isSynchronizeCall()
{
return synchronizeCall;
}
public void setSynchronizeCall(boolean synchronizeCall)
{
this.synchronizeCall = synchronizeCall;
}
@Override
public String toString()
{
final StringBuffer sb = new StringBuffer();
sb.append("AbstractEntryPointResolver");
sb.append(", acceptVoidMethods=").append(acceptVoidMethods);
sb.append('}');
return sb.toString();
}
}