View Javadoc

1   /*
2    * $Id: AbstractMessageSplitter.java 9327 2007-10-24 13:18:33Z holger $
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.config.MuleProperties;
14  import org.mule.umo.UMOException;
15  import org.mule.umo.UMOMessage;
16  import org.mule.umo.UMOSession;
17  import org.mule.umo.endpoint.UMOEndpoint;
18  import org.mule.umo.routing.CouldNotRouteOutboundMessageException;
19  import org.mule.umo.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
26   * split the contents of a received message into sub parts that can be processed by
27   * other components. Each Part is fired as a separate event to each endpoint on the
28   * router. The endpoints can have filters on them to receive only certain message
29   * parts.
30   */
31  public abstract class AbstractMessageSplitter extends FilteringOutboundRouter
32  {
33      // Determines if the same endpoint will be matched multiple times until a
34      // match is not found. This should be set by overriding classes.
35      protected boolean multimatch = true;
36  
37      // flag which, if true, makes the splitter honour settings such as remoteSync and
38      // synchronous on the endpoint
39      protected boolean honorSynchronicity = false;
40  
41      public UMOMessage route(UMOMessage message, UMOSession session, boolean synchronous)
42          throws RoutingException
43      {
44          String correlationId = (String) propertyExtractor.getProperty(
45              MuleProperties.MULE_CORRELATION_ID_PROPERTY, message);
46  
47          this.initialise(message);
48  
49          UMOEndpoint endpoint;
50          UMOMessage result = null;
51          List list = getEndpoints();
52          int correlationSequence = 1;
53          for (Iterator iterator = list.iterator(); iterator.hasNext();)
54          {
55              endpoint = (UMOEndpoint) iterator.next();
56              message = getMessagePart(message, endpoint);
57              // TODO MULE-1378
58              if (message == null)
59              {
60                  // Log a warning if there are no messages for a given endpoint
61                  logger.warn("Message part is null for endpoint: " + endpoint.getEndpointURI().toString());
62              }
63  
64              // We'll keep looping to get all messages for the current endpoint
65              // before moving to the next endpoint
66              // This can be turned off by setting the multimatch flag to false
67              while (message != null)
68              {
69                  if (honorSynchronicity)
70                  {
71                      synchronous = endpoint.isSynchronous();
72                  }
73                  try
74                  {
75                      if (enableCorrelation != ENABLE_CORRELATION_NEVER)
76                      {
77                          boolean correlationSet = message.getCorrelationId() != null;
78                          if (!correlationSet && (enableCorrelation == ENABLE_CORRELATION_IF_NOT_SET))
79                          {
80                              message.setCorrelationId(correlationId);
81                          }
82  
83                          // take correlation group size from the message
84                          // properties, set by concrete message splitter
85                          // implementations
86                          final int groupSize = message.getCorrelationGroupSize();
87                          message.setCorrelationGroupSize(groupSize);
88                          message.setCorrelationSequence(correlationSequence++);
89                      }
90  
91                      if (honorSynchronicity)
92                      {
93                          message.setBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY,
94                              endpoint.isRemoteSync());
95                      }
96  
97                      if (synchronous)
98                      {
99                          result = send(session, message, endpoint);
100                     }
101                     else
102                     {
103                         dispatch(session, message, endpoint);
104                     }
105                 }
106                 catch (UMOException e)
107                 {
108                     throw new CouldNotRouteOutboundMessageException(message, endpoint, e);
109                 }
110 
111                 if (!multimatch)
112                 {
113                     break;
114                 }
115 
116                 message = this.getMessagePart(message, endpoint);
117             }
118         }
119 
120         // we are done with splitting & routing
121         this.cleanup();
122 
123         return result;
124     }
125 
126     /**
127      * This method can be implemented to split the message up before
128      * {@link #getMessagePart(UMOMessage, UMOEndpoint)} method is called.
129      * 
130      * @param message the message being routed
131      */
132     protected void initialise(UMOMessage message)
133     {
134         // nothing to do; subclasses need to implement this
135     }
136 
137     /**
138      * This method is called after all parts of the original message have been processed;
139      * typically this is the case after {@link #getMessagePart(UMOMessage, UMOEndpoint)}
140      * returned <code>null</code>.
141      */
142     protected void cleanup()
143     {
144         // nothing to do; subclasses need to implement this
145 
146         // MULE-2600 note: this method (as well as initialise()) should be abstract to force
147         // proper implementation by the subclass, but doing so would break compatibility with
148         // exisiting custom splitters..
149     }
150 
151     public boolean isHonorSynchronicity()
152     {
153         return honorSynchronicity;
154     }
155 
156     /**
157      * Sets the flag indicating whether the splitter honurs endpoint settings
158      * 
159      * @param honorSynchronicity flag setting
160      */
161     public void setHonorSynchronicity(boolean honorSynchronicity)
162     {
163         this.honorSynchronicity = honorSynchronicity;
164     }
165 
166     /**
167      * Retrieves a specific message part for the given endpoint. the message will
168      * then be routed via the provider. <p/> <strong>NOTE:</strong>Implementations
169      * must provide proper synchronization for shared state (payload, properties,
170      * etc.)
171      * 
172      * @param message the current message being processed
173      * @param endpoint the endpoint that will be used to route the resulting message
174      *            part
175      * @return the message part to dispatch
176      */
177     protected abstract UMOMessage getMessagePart(UMOMessage message, UMOEndpoint endpoint);
178 }