View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.routing.outbound;
8   
9   import org.mule.DefaultMuleMessage;
10  import org.mule.api.MuleEvent;
11  import org.mule.api.MuleException;
12  import org.mule.api.MuleMessage;
13  import org.mule.api.processor.MessageProcessor;
14  import org.mule.api.processor.MessageRouter;
15  import org.mule.api.routing.CouldNotRouteOutboundMessageException;
16  import org.mule.api.routing.RoutingException;
17  import org.mule.routing.CorrelationMode;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  
24  /**
25   * <code>AbstractMessageSplitter</code> is an outbound Message Splitter used to split
26   * the contents of a received message into sub parts that can be processed by other
27   * components. Each Part is fired as a separate event to each endpoint on the router. The
28   * targets can have filters on them to receive only certain message parts.
29   */
30  public abstract class AbstractMessageSplitter extends FilteringOutboundRouter implements MessageRouter
31  {
32      @Override
33      public MuleEvent route(MuleEvent event) throws RoutingException
34      {
35          MuleMessage message = event.getMessage();
36  
37          String correlationId = event.getFlowConstruct().getMessageInfoMapping().getCorrelationId(message);
38  
39          List<MuleEvent> results = new ArrayList<MuleEvent>();
40          int correlationSequence = 1;
41          SplitMessage splitMessage = getMessageParts(message, getRoutes());
42  
43          // Cache the properties here because for some message types getting the
44          // properties can be expensive
45          Map props = new HashMap();
46          for (String propertyKey : message.getOutboundPropertyNames())
47          {
48              Object value = message.getOutboundProperty(propertyKey);
49              if (value != null)
50              {
51                  props.put(propertyKey, value);
52              }
53          }
54  
55          for (int i = 0; i < splitMessage.size(); i++)
56          {
57              SplitMessage.MessagePart part = splitMessage.getPart(i);
58  
59              MuleMessage sendMessage;
60              if (part.getPart() instanceof MuleMessage)
61              {
62                  sendMessage = (MuleMessage) part.getPart();
63              }
64              else
65              {
66                  sendMessage = new DefaultMuleMessage(part.getPart(), props, muleContext);
67              }
68  
69              try
70              {
71                  if (enableCorrelation != CorrelationMode.NEVER)
72                  {
73                      boolean correlationSet = message.getCorrelationId() != null;
74                      if (!correlationSet && (enableCorrelation == CorrelationMode.IF_NOT_SET))
75                      {
76                          sendMessage.setCorrelationId(correlationId);
77                      }
78  
79                      // take correlation group size from the message properties, set by concrete 
80                      // message splitter implementations
81                      sendMessage.setCorrelationGroupSize(splitMessage.size());
82                      sendMessage.setCorrelationSequence(correlationSequence++);
83                  }
84  
85                  if (part.getEndpoint().getExchangePattern().hasResponse())
86                  {
87                      results.add(sendRequest(event, sendMessage, part.getEndpoint(), true));
88                  }
89                  else
90                  {
91                      sendRequest(event, sendMessage, part.getEndpoint(), false);
92                  }
93              }
94              catch (MuleException e)
95              {
96                  throw new CouldNotRouteOutboundMessageException(event, part.getEndpoint(), e);
97              }
98          }
99  
100         return resultsHandler.aggregateResults(results, event, muleContext);
101     }
102 
103 
104     /**
105      * Implementing classes should create a {@link org.mule.routing.outbound.SplitMessage} instance and for
106      * each part can associate an endpoint.
107      * Note that No state should be stored on the router itself. The {@link SplitMessage} provides the parts and
108      * endpoint mapping info in order for the correct dispatching to occur.
109      * <p/>
110      * If users do not want to associate a message part with an endpoint, but just dispatch parts over the targets in
111      * a round-robin way, they should use the {@link org.mule.routing.outbound.AbstractRoundRobinMessageSplitter} instead.
112      *
113      * @param message   the current message being processed
114      * @param endpoints A list of {@link org.mule.api.endpoint.OutboundEndpoint} that will be used to dispatch each of the parts
115      * @return a {@link org.mule.routing.outbound.SplitMessage} instance that contains the message parts and the
116      *         endpoint to associate with the message part.
117      * @see org.mule.routing.outbound.SplitMessage
118      * @see org.mule.routing.outbound.AbstractRoundRobinMessageSplitter
119      */
120     protected abstract SplitMessage getMessageParts(MuleMessage message, List <MessageProcessor> endpoints);
121 
122 }