Package org.mule.routing.outbound

Source Code of org.mule.routing.outbound.AbstractOutboundRouter

/*
* $Id: AbstractOutboundRouter.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.routing.outbound;

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.config.MuleProperties;
import org.mule.api.construct.FlowConstruct;
import org.mule.api.construct.FlowConstructAware;
import org.mule.api.context.MuleContextAware;
import org.mule.api.endpoint.OutboundEndpoint;
import org.mule.api.lifecycle.Disposable;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.lifecycle.Startable;
import org.mule.api.lifecycle.Stoppable;
import org.mule.api.processor.MessageProcessor;
import org.mule.api.routing.OutboundRouter;
import org.mule.api.routing.RouterResultsHandler;
import org.mule.api.routing.RoutingException;
import org.mule.api.transaction.TransactionCallback;
import org.mule.api.transaction.TransactionConfig;
import org.mule.api.transport.DispatchException;
import org.mule.config.i18n.CoreMessages;
import org.mule.management.stats.RouterStatistics;
import org.mule.processor.AbstractMessageProcessorOwner;
import org.mule.routing.CorrelationMode;
import org.mule.routing.DefaultRouterResultsHandler;
import org.mule.transaction.TransactionTemplate;
import org.mule.util.StringMessageUtils;
import org.mule.util.SystemUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

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

/**
* <code>AbstractOutboundRouter</code> is a base router class that tracks statistics about message processing
* through the router.
*/
public abstract class AbstractOutboundRouter extends AbstractMessageProcessorOwner implements OutboundRouter
{
    /**
     * These properties are automatically propagated by Mule from inbound to outbound
     */
    protected static List<String> magicProperties = Arrays.asList(
        MuleProperties.MULE_CORRELATION_ID_PROPERTY, MuleProperties.MULE_CORRELATION_ID_PROPERTY,
        MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY,
        MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY, MuleProperties.MULE_SESSION_PROPERTY);

    /**
     * logger used by this class
     */
    protected transient Log logger = LogFactory.getLog(getClass());

    @SuppressWarnings("unchecked")
    protected List<MessageProcessor> routes = new CopyOnWriteArrayList();

    protected String replyTo = null;

    /**
     * Determines if Mule stamps outgoing message with a correlation ID or not.
     */
    protected CorrelationMode enableCorrelation = CorrelationMode.IF_NOT_SET;

    protected TransactionConfig transactionConfig;

    protected RouterResultsHandler resultsHandler = new DefaultRouterResultsHandler();

    private RouterStatistics routerStatistics;

    protected AtomicBoolean initialised = new AtomicBoolean(false);
    protected AtomicBoolean started = new AtomicBoolean(false);

    public MuleEvent process(final MuleEvent event) throws MuleException
    {
        TransactionTemplate<MuleEvent> tt = new TransactionTemplate<MuleEvent>(getTransactionConfig(),
            muleContext);

        TransactionCallback<MuleEvent> cb = new TransactionCallback<MuleEvent>()
        {
            public MuleEvent doInTransaction() throws Exception
            {
                return route(event);
            }
        };
        try
        {
            return tt.execute(cb);
        }
        catch (RoutingException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new RoutingException(event, this, e);
        }
    }

    protected abstract MuleEvent route(MuleEvent event) throws MessagingException;

    protected final MuleEvent sendRequest(final MuleEvent routedEvent,
                                          final MuleMessage message,
                                          final MessageProcessor route,
                                          boolean awaitResponse) throws MuleException
    {
        if (awaitResponse && replyTo != null)
        {
            logger.debug("event was dispatched synchronously, but there is a ReplyTo route set, so using asynchronous dispatch");
            awaitResponse = false;
        }

        setMessageProperties(routedEvent.getSession().getFlowConstruct(), message, route);

        if (logger.isDebugEnabled())
        {
            if (route instanceof OutboundEndpoint)
            {
                logger.debug("Message being sent to: " + ((OutboundEndpoint) route).getEndpointURI());
            }
            logger.debug(message);
        }

        if (logger.isTraceEnabled())
        {
            try
            {
                logger.trace("Request payload: \n"
                             + StringMessageUtils.truncate(message.getPayloadForLogging(), 100, false));
                if (route instanceof OutboundEndpoint)
                {
                    logger.trace("outbound transformer is: " + ((OutboundEndpoint) route).getTransformers());
                }
            }
            catch (Exception e)
            {
                logger.trace("Request payload: \n(unable to retrieve payload: " + e.getMessage());
                if (route instanceof OutboundEndpoint)
                {
                    logger.trace("outbound transformer is: " + ((OutboundEndpoint) route).getTransformers());
                }
            }
        }

        MuleEvent result;
        try
        {
            result = sendRequestEvent(routedEvent, message, route, awaitResponse);
        }
        catch (MessagingException me)
        {
            throw me;
        }
        catch (Exception e)
        {
            throw new RoutingException(routedEvent, null, e);
        }

        if (getRouterStatistics() != null)
        {
            if (getRouterStatistics().isEnabled())
            {
                getRouterStatistics().incrementRoutedMessage(route);
            }
        }

        if (result != null)
        {
            MuleMessage resultMessage = result.getMessage();
            if (logger.isTraceEnabled())
            {
                if (resultMessage != null)
                {
                    try
                    {
                        logger.trace("Response payload: \n"
                                     + StringMessageUtils.truncate(resultMessage.getPayloadForLogging(), 100,
                                         false));
                    }
                    catch (Exception e)
                    {
                        logger.trace("Response payload: \n(unable to retrieve payload: " + e.getMessage());
                    }
                }
            }
        }

        return result;
    }

    protected void setMessageProperties(FlowConstruct service, MuleMessage message, MessageProcessor route)
    {
        if (replyTo != null)
        {
            // if replyTo is set we'll probably want the correlationId set as
            // well
            message.setReplyTo(replyTo);
            message.setOutboundProperty(MuleProperties.MULE_REPLY_TO_REQUESTOR_PROPERTY, service.getName());
            if (logger.isDebugEnabled() && route instanceof OutboundEndpoint)
            {
                logger.debug("Setting replyTo=" + replyTo + " for outbound route: "
                             + ((OutboundEndpoint) route).getEndpointURI());
            }
        }
        if (enableCorrelation != CorrelationMode.NEVER)
        {
            boolean correlationSet = message.getCorrelationId() != null;
            if (correlationSet && (enableCorrelation == CorrelationMode.IF_NOT_SET))
            {
                if (logger.isDebugEnabled())
                {
                    logger.debug("CorrelationId is already set to '" + message.getCorrelationId()
                                 + "' , not setting it again");
                }
                return;
            }
            else if (correlationSet)
            {
                if (logger.isDebugEnabled())
                {
                    logger.debug("CorrelationId is already set to '" + message.getCorrelationId()
                                 + "', but router is configured to overwrite it");
                }
            }
            else
            {
                if (logger.isDebugEnabled())
                {
                    logger.debug("No CorrelationId is set on the message, will set a new Id");
                }
            }

            String correlation;
            correlation = service.getMessageInfoMapping().getCorrelationId(message);
            if (logger.isDebugEnabled())
            {
                logger.debug("Extracted correlation Id as: " + correlation);
            }

            if (logger.isDebugEnabled())
            {
                StringBuffer buf = new StringBuffer();
                buf.append("Setting Correlation info on Outbound router");
                if (route instanceof OutboundEndpoint)
                {
                    buf.append(" for endpoint: ").append(((OutboundEndpoint) route).getEndpointURI());
                }
                buf.append(SystemUtils.LINE_SEPARATOR).append("Id=").append(correlation);
                // buf.append(", ").append("Seq=").append(seq);
                // buf.append(", ").append("Group Size=").append(group);
                logger.debug(buf.toString());
            }
            message.setCorrelationId(correlation);
            // message.setCorrelationGroupSize(group);
            // message.setCorrelationSequence(seq);
        }
    }

    public List<MessageProcessor> getRoutes()
    {
        return routes;
    }

    /*
     * For spring access
     */
    // TODO Use spring factory bean
    @Deprecated
    public void setMessageProcessors(List<MessageProcessor> routes) throws MuleException
    {
        setRoutes(routes);
    }

    public void setRoutes(List<MessageProcessor> routes) throws MuleException
    {
        this.routes.clear();
        for (MessageProcessor route : routes)
        {
            addRoute(route);
        }
    }

    public synchronized void addRoute(MessageProcessor route) throws MuleException
    {
        if (initialised.get())
        {
            if (route instanceof MuleContextAware)
            {
                ((MuleContextAware) route).setMuleContext(muleContext);
            }
            if (route instanceof FlowConstructAware)
            {
                ((FlowConstructAware) route).setFlowConstruct(flowConstruct);
            }
            if (route instanceof Initialisable)
            {
                ((Initialisable) route).initialise();
            }
        }
        if (started.get())
        {
            if (route instanceof Startable)
            {
                ((Startable) route).start();
            }
        }
        routes.add(route);
    }

    public synchronized void removeRoute(MessageProcessor route) throws MuleException
    {
        if (started.get())
        {
            if (route instanceof Stoppable)
            {
                ((Stoppable) route).stop();
            }
        }
        if (initialised.get())
        {
            if (route instanceof Disposable)
            {
                ((Disposable) route).dispose();
            }
        }
        routes.remove(route);
    }

    public String getReplyTo()
    {
        return replyTo;
    }

    public void setReplyTo(String replyTo)
    {
        this.replyTo = replyTo;
    }

    public CorrelationMode getEnableCorrelation()
    {
        return enableCorrelation;
    }

    public void setEnableCorrelation(CorrelationMode enableCorrelation)
    {
        this.enableCorrelation = enableCorrelation;
    }

    public void setEnableCorrelationAsString(String enableCorrelation)
    {
        if (enableCorrelation != null)
        {
            if (enableCorrelation.equals("ALWAYS"))
            {
                this.enableCorrelation = CorrelationMode.ALWAYS;
            }
            else if (enableCorrelation.equals("NEVER"))
            {
                this.enableCorrelation = CorrelationMode.NEVER;
            }
            else if (enableCorrelation.equals("IF_NOT_SET"))
            {
                this.enableCorrelation = CorrelationMode.IF_NOT_SET;
            }
            else
            {
                throw new IllegalArgumentException("Value for enableCorrelation not recognised: "
                                                   + enableCorrelation);
            }
        }
    }

    public TransactionConfig getTransactionConfig()
    {
        return transactionConfig;
    }

    public void setTransactionConfig(TransactionConfig transactionConfig)
    {
        this.transactionConfig = transactionConfig;
    }

    public boolean isDynamicRoutes()
    {
        return false;
    }

    /**
     * @param name the route identifier
     * @return the route or null if the endpoint's Uri is not registered
     */
    public MessageProcessor getRoute(String name)
    {
        for (MessageProcessor route : routes)
        {
            if (route instanceof OutboundEndpoint)
            {
                OutboundEndpoint endpoint = (OutboundEndpoint) route;
                if (endpoint.getName().equals(name))
                {
                    return endpoint;
                }
            }
        }
        return null;
    }

    public RouterResultsHandler getResultsHandler()
    {
        return resultsHandler;
    }

    public void setResultsHandler(RouterResultsHandler resultsHandler)
    {
        this.resultsHandler = resultsHandler;
    }

    /**
     * Send message event to destination.
     */
    protected MuleEvent sendRequestEvent(MuleEvent routedEvent,
                                         MuleMessage message,
                                         MessageProcessor route,
                                         boolean awaitResponse) throws MuleException
    {
        if (route == null)
        {
            throw new DispatchException(CoreMessages.objectIsNull("Outbound Endpoint"), routedEvent, null);
        }

        MuleEvent event = createEventToRoute(routedEvent, message, route);

        if (awaitResponse)
        {
            int timeout = message.getOutboundProperty(MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, -1);
            if (timeout >= 0)
            {
                event.setTimeout(timeout);
            }
        }

        return route.process(event);
    }

    /**
     * Create a new event to be routed to the target MP
     */
    protected MuleEvent createEventToRoute(MuleEvent routedEvent, MuleMessage message, MessageProcessor route)
    {
        MuleEvent event = new DefaultMuleEvent(message, routedEvent.getEndpoint(), routedEvent.getSession(), routedEvent.getProcessingTime());
        return event;
    }

    /**
     * Create a fresh copy of a message.
     */
    protected MuleMessage cloneMessage(MuleMessage message)
    {
        MuleMessage clonedMessage = new DefaultMuleMessage(message.getPayload(), message, muleContext);
        return clonedMessage;
    }

    /**
     * Propagates a number of internal system properties to handle correlation, session, etc. Note that in and
     * out params can be the same message object when not dealing with replies.
     *
     * @see #magicProperties
     */
    protected void propagateMagicProperties(MuleMessage in, MuleMessage out)
    {
        for (String name : magicProperties)
        {
            Object value = in.getInboundProperty(name);
            if (value != null)
            {
                out.setOutboundProperty(name, value);
            }
        }
    }

    public void initialise() throws InitialisationException
    {
        synchronized (routes)
        {
            super.initialise();
            initialised.set(true);
        }
    }

    public void dispose()
    {
        synchronized (routes)
        {
            super.dispose();
            routes = Collections.<MessageProcessor> emptyList();
            initialised.set(false);
        }
    }

    public void start() throws MuleException
    {
        synchronized (routes)
        {
            super.start();
            started.set(true);
        }
    }

    public void stop() throws MuleException
    {
        synchronized (routes)
        {
            super.stop();
            started.set(false);
        }
    }

    public MuleContext getMuleContext()
    {
        return muleContext;
    }

    public void setRouterStatistics(RouterStatistics stats)
    {
        this.routerStatistics = stats;
    }

    public RouterStatistics getRouterStatistics()
    {
        return routerStatistics;
    }

    @Override
    protected List<MessageProcessor> getOwnedMessageProcessors()
    {
        return routes;
    }
}
TOP

Related Classes of org.mule.routing.outbound.AbstractOutboundRouter

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.