Package org.mule.processor

Source Code of org.mule.processor.InvokerMessageProcessor

/*
* $Id: InvokerMessageProcessor.java 21307 2011-02-17 15:35:44Z dfeist $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.processor;

import org.mule.DefaultMuleEvent;
import org.mule.DefaultMuleMessage;
import org.mule.api.MessagingException;
import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.context.MuleContextAware;
import org.mule.api.expression.ExpressionManager;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.processor.MessageProcessor;
import org.mule.api.registry.RegistrationException;
import org.mule.api.transformer.DataType;
import org.mule.api.transformer.Transformer;
import org.mule.api.transformer.TransformerException;
import org.mule.config.i18n.CoreMessages;
import org.mule.transformer.TransformerTemplate;
import org.mule.transformer.types.DataTypeFactory;
import org.mule.transport.NullPayload;
import org.mule.util.ClassUtils;
import org.mule.util.TemplateParser;
import org.mule.util.TemplateParser.PatternInfo;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* <code>InvokerMessageProcessor</code> invokes a specified method of an object. An
* array of argument expressions can be provided to map the message to the method
* arguments. The method used is determined by the method name along with the number
* of argument expressions provided. The results of the expression evaluations will
* automatically be transformed where possible to the method argument type. Multiple
* methods with the same name and same number of arguments are not supported
* currently.
*/
public class InvokerMessageProcessor implements MessageProcessor, Initialisable, MuleContextAware
{
    protected final transient Log logger = LogFactory.getLog(getClass());

    protected Object object;
    protected Class<?> objectType;
    protected String methodName;
    protected List<?> arguments = new ArrayList<Object>();;
    protected Class<?>[] argumentTypes;
    protected String name;
    protected PatternInfo patternInfo = TemplateParser.createMuleStyleParser().getStyle();

    protected Method method;
    protected ExpressionManager expressionManager;
    protected MuleContext muleContext;

    public void initialise() throws InitialisationException
    {
        if (object == null)
        {
            lookupObjectInstance();
        }

        resolveMethodToInvoke();

        expressionManager = muleContext.getExpressionManager();
    }

    protected void resolveMethodToInvoke() throws InitialisationException
    {
        if (argumentTypes != null)
        {
            method = ClassUtils.getMethod(object.getClass(), methodName, argumentTypes);
            if (method == null)
            {
                throw new InitialisationException(CoreMessages.methodWithParamsNotFoundOnObject(methodName,
                    argumentTypes, object.getClass()), this);
            }
        }
        else
        {
            List<Method> matchingMethods = new ArrayList<Method>();
            int argSize = arguments != null ? arguments.size() : 0;
            for (Method methodCandidate : object.getClass().getMethods())
            {
                if (methodCandidate.getName().equals(methodName)
                    && methodCandidate.getParameterTypes().length == argSize)
                    matchingMethods.add(methodCandidate);
            }
            if (matchingMethods.size() == 1)
            {
                method = matchingMethods.get(0);
                argumentTypes = method.getParameterTypes();
            }
            else
            {
                throw new InitialisationException(CoreMessages.methodWithNumParamsNotFoundOnObject(
                    methodName, arguments.size(), object), this);
            }
        }

        if (logger.isDebugEnabled())
        {
            logger.debug(String.format("Initialised %s to use method: '%s'", this, method));
        }
    }

    protected void lookupObjectInstance() throws InitialisationException
    {
        if (logger.isDebugEnabled())
        {
            logger.debug(String.format(
                "No object instance speciedied.  Looking up single instance of type %s in mule registry",
                objectType));
        }

        try
        {
            object = muleContext.getRegistry().lookupObject(objectType);
        }
        catch (RegistrationException e)
        {
            throw new InitialisationException(
                CoreMessages.initialisationFailure(String.format(
                    "Muliple instances of '%s' were found in the registry so you need to configure a specific instance",
                    objectType)), this);
        }
        if (object == null)
        {
            throw new InitialisationException(CoreMessages.initialisationFailure(String.format(
                "No instance of '%s' was found in the registry", objectType)), this);

        }
    }

    public MuleEvent process(MuleEvent event) throws MuleException
    {
        MuleEvent resultEvent = event;
        Object[] args = evaluateArguments(event, arguments);

        if (logger.isDebugEnabled())
        {
            logger.debug(String.format("Invoking  '%s' of '%s' with arguments: '%s'", method.getName(),
                object, args));
        }

        try
        {
            Object result = method.invoke(object, args);
            if (!method.getReturnType().equals(void.class))
            {
                resultEvent = createResultEvent(event, result);
            }
        }
        catch (Exception e)
        {
            throw new MessagingException(CoreMessages.failedToInvoke(object.toString()), event, e);
        }
        return resultEvent;
    }

    protected Object[] evaluateArguments(MuleEvent event, List<?> argumentTemplates)
        throws MessagingException
    {
        int argSize = argumentTemplates != null ? argumentTemplates.size() : 0;
        Object[] args = new Object[argSize];
        MuleMessage message = event.getMessage();
        try
        {
            for (int i = 0; i < args.length; i++)
            {
                Object argumentTemplate = argumentTemplates.get(i);
                if (argumentTemplate != null)
                {
                    args[i] = transformArgument(evaluateExpressionCandidate(argumentTemplate, message),
                        argumentTypes[i]);
                }
            }
            return args;
        }
        catch (TransformerException e)
        {
            throw new MessagingException(event, e);
        }
    }

    @SuppressWarnings("unchecked")
    protected Object evaluateExpressionCandidate(Object expressionCandidate, MuleMessage message)
        throws TransformerException
    {
        if (expressionCandidate instanceof Collection<?>)
        {
            Collection<Object> collectionTemplate = (Collection<Object>) expressionCandidate;
            Collection<Object> newCollection = new ArrayList<Object>();
            for (Object object : collectionTemplate)
            {
                newCollection.add(evaluateExpressionCandidate(object, message));
            }
            return newCollection;
        }
        else if (expressionCandidate instanceof Map<?, ?>)
        {
            Map<Object, Object> mapTemplate = (Map<Object, Object>) expressionCandidate;
            Map<Object, Object> newMap = new HashMap<Object, Object>();
            for (Entry<Object, Object> entry : mapTemplate.entrySet())
            {
                newMap.put(evaluateExpressionCandidate(entry.getKey(), message), evaluateExpressionCandidate(
                    entry.getValue(), message));
            }
            return newMap;
        }
        else if (expressionCandidate instanceof String[])
        {
            String[] stringArrayTemplate = (String[]) expressionCandidate;
            Object[] newArray = new String[stringArrayTemplate.length];
            for (int j = 0; j < stringArrayTemplate.length; j++)
            {
                newArray[j] = evaluateExpressionCandidate(stringArrayTemplate[j], message);
            }
            return newArray;
        }
        if (expressionCandidate instanceof String)
        {
            Object arg;
            String expression = (String) expressionCandidate;
            // If string contains is a single expression then evaluate otherwise
            // parse. We can't use parse() always because that will convert
            // everything to a string
            if (expression.startsWith(patternInfo.getPrefix())
                && expression.endsWith(patternInfo.getSuffix()))
            {
                arg = expressionManager.evaluate(expression, message);
            }
            else
            {
                arg = expressionManager.parse(expression, message);
            }

            // If expression evaluates to a MuleMessage then use it's payload
            if (arg instanceof MuleMessage)
            {
                arg = ((MuleMessage) arg).getPayload();
            }
            return arg;
        }
        else
        {
            // Not an expression so use object itself
            return expressionCandidate;
        }
    }

    private Object transformArgument(Object arg, Class<?> type) throws TransformerException
    {
        if (!(type.isAssignableFrom(arg.getClass())))
        {
            DataType<?> source = DataTypeFactory.create(arg.getClass());
            DataType<?> target = DataTypeFactory.create(type);
            // Throws TransformerException if no suitable transformer is found
            Transformer t = muleContext.getRegistry().lookupTransformer(source, target);
            arg = t.transform(arg);
        }
        return arg;
    }

    public void setObject(Object object)
    {
        this.object = object;
    }

    public void setMethodName(String methodName)
    {
        this.methodName = methodName;
    }

    public void setArgumentExpressionsString(String arguments)
    {
        this.arguments = Arrays.asList(arguments.split("\\s*,\\s*"));
    }

    public void setArguments(List<?> arguments)
    {
        this.arguments = arguments;
    }

    protected MuleEvent createResultEvent(MuleEvent event, Object result) throws MuleException
    {
        if (result instanceof MuleMessage)
        {
            return new DefaultMuleEvent((MuleMessage) result, event);
        }
        else if (result != null)
        {
            event.getMessage().applyTransformers(
                event,
                Collections.<Transformer> singletonList(new TransformerTemplate(
                    new TransformerTemplate.OverwitePayloadCallback(result))));
            return event;
        }
        else
        {
            return new DefaultMuleEvent(new DefaultMuleMessage(NullPayload.getInstance(),
                event.getMuleContext()), event);
        }
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public void setArgumentTypes(Class<?>[] argumentTypes)
    {
        this.argumentTypes = argumentTypes;
    }

    @Override
    public String toString()
    {
        return String.format(
            "InvokerMessageProcessor [name=%s, object=%s, methodName=%s, argExpressions=%s, argTypes=%s]",
            name, object, methodName, arguments, argumentTypes);
    }

    public void setMuleContext(MuleContext context)
    {
        this.muleContext = context;
    }

    public void setObjectType(Class<?> objectType)
    {
        this.objectType = objectType;
    }

}
TOP

Related Classes of org.mule.processor.InvokerMessageProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.