View Javadoc

1   /*
2    * $Id: AbstractMessageSplitter.java 11475 2008-03-21 22:46:33Z rossmason $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.routing.outbound;
12  
13  import org.mule.api.MuleException;
14  import org.mule.api.MuleMessage;
15  import org.mule.api.MuleSession;
16  import org.mule.api.config.MuleProperties;
17  import org.mule.api.endpoint.OutboundEndpoint;
18  import org.mule.api.routing.CouldNotRouteOutboundMessageException;
19  import org.mule.api.routing.RoutingException;
20  
21  import java.util.Iterator;
22  import java.util.List;
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   * endpoints can have filters on them to receive only certain message parts.
29   */
30  public abstract class AbstractMessageSplitter extends FilteringOutboundRouter
31  {
32      // Determines if the same endpoint will be matched multiple times until a
33      // match is not found. This should be set by overriding classes.
34      protected boolean multimatch = true;
35  
36      // flag which, if true, makes the splitter honour settings such as remoteSync and
37      // synchronous on the endpoint
38      protected boolean honorSynchronicity = false;
39  
40      public MuleMessage route(MuleMessage message, MuleSession session, boolean synchronous)
41          throws RoutingException
42      {
43          String correlationId = messageInfoMapping.getCorrelationId(message);
44  
45          this.initialise(message);
46  
47          OutboundEndpoint endpoint;
48          MuleMessage result = null;
49          List list = getEndpoints();
50          int correlationSequence = 1;
51          for (Iterator iterator = list.iterator(); iterator.hasNext();)
52          {
53              endpoint = (OutboundEndpoint) iterator.next();
54              message = getMessagePart(message, endpoint);
55              // TODO MULE-1378
56              if (message == null)
57              {
58                  // Log a warning if there are no messages for a given endpoint
59                  logger.warn("Message part is null for endpoint: " + endpoint.getEndpointURI().toString());
60              }
61  
62              // We'll keep looping to get all messages for the current endpoint
63              // before moving to the next endpoint
64              // This can be turned off by setting the multimatch flag to false
65              while (message != null)
66              {
67                  if (honorSynchronicity)
68                  {
69                      synchronous = endpoint.isSynchronous();
70                  }
71                  try
72                  {
73                      if (enableCorrelation != ENABLE_CORRELATION_NEVER)
74                      {
75                          boolean correlationSet = message.getCorrelationId() != null;
76                          if (!correlationSet && (enableCorrelation == ENABLE_CORRELATION_IF_NOT_SET))
77                          {
78                              message.setCorrelationId(correlationId);
79                          }
80  
81                          // take correlation group size from the message
82                          // properties, set by concrete message splitter
83                          // implementations
84                          final int groupSize = message.getCorrelationGroupSize();
85                          message.setCorrelationGroupSize(groupSize);
86                          message.setCorrelationSequence(correlationSequence++);
87                      }
88  
89                      if (honorSynchronicity)
90                      {
91                          message.setBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY,
92                              endpoint.isRemoteSync());
93                      }
94  
95                      if (synchronous)
96                      {
97                          result = send(session, message, endpoint);
98                      }
99                      else
100                     {
101                         dispatch(session, message, endpoint);
102                     }
103                 }
104                 catch (MuleException e)
105                 {
106                     throw new CouldNotRouteOutboundMessageException(message, endpoint, e);
107                 }
108 
109                 if (!multimatch)
110                 {
111                     break;
112                 }
113 
114                 message = this.getMessagePart(message, endpoint);
115             }
116         }
117 
118         // we are done with splitting & routing
119         this.cleanup();
120 
121         return result;
122     }
123 
124     public boolean isHonorSynchronicity()
125     {
126         return honorSynchronicity;
127     }
128 
129     /**
130      * Sets the flag indicating whether the splitter honurs endpoint settings
131      * 
132      * @param honorSynchronicity flag setting
133      */
134     public void setHonorSynchronicity(boolean honorSynchronicity)
135     {
136         this.honorSynchronicity = honorSynchronicity;
137     }
138 
139     /**
140      * This method can be implemented to split the message up before
141      * {@link #getMessagePart(MuleMessage, OutboundEndpoint)} method is called.
142      * 
143      * @param message the message being routed
144      */
145     protected abstract void initialise(MuleMessage message);
146 
147     /**
148      * Retrieves a specific message part for the given endpoint. the message will then be
149      * routed via the provider. <p/> <strong>NOTE:</strong>Implementations must provide
150      * proper synchronization for shared state (payload, properties, etc.)
151      * 
152      * @param message the current message being processed
153      * @param endpoint the endpoint that will be used to route the resulting message part
154      * @return the message part to dispatch
155      */
156     protected abstract MuleMessage getMessagePart(MuleMessage message, OutboundEndpoint endpoint);
157 
158     /**
159      * This method is called after all parts of the original message have been processed;
160      * typically this is the case after {@link #getMessagePart(MuleMessage, OutboundEndpoint)}
161      * returned <code>null</code>.
162      */
163     protected abstract void cleanup();
164 
165 }