View Javadoc

1   /*
2    * $Id: RoundRobinXmlSplitter.java 11567 2008-04-11 13:08:05Z dirk.olmes $
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.module.xml.routing;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.MuleSession;
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.HashMap;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  
26  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
27  
28  import org.dom4j.Document;
29  
30  /**
31   * This router will split the Xml message into parts based on the xpath expression
32   * and route each new event to the endpoints on the router, one after the other.
33   */
34  public class RoundRobinXmlSplitter extends FilteringXmlMessageSplitter
35  {
36      // We have to do some additional checks if we're going to allow filters on the
37      // round robin endpoints
38      // So for performance lets turn it off by default
39      protected volatile boolean enableEndpointFiltering = false;
40      private boolean deterministic = true;
41      private static final AtomicInteger globalCounter = new AtomicInteger(0);
42  
43      public MuleMessage route(MuleMessage message, MuleSession session, boolean synchronous)
44          throws RoutingException
45      {
46          try
47          {
48              String correlationId = messageInfoMapping.getCorrelationId(message);
49              initialise(message);
50  
51              OutboundEndpoint endpoint;
52              MuleMessage result = null;
53              Document part;
54              List parts = (List)nodesContext.get();
55              if (parts == null)
56              {
57                  logger.error("There are no parts for current message. No events were routed: " + message);
58                  return null;
59              }
60              int correlationSequence = 1;
61              Counter epCounter = new Counter();
62              Iterator iterator = parts.iterator();
63              while (iterator.hasNext())
64              {
65                  part = (Document)iterator.next();
66                  // Create the message
67                  Map theProperties = (Map)propertiesContext.get();
68                  message = new DefaultMuleMessage(part, new HashMap(theProperties));
69  
70                  if (enableEndpointFiltering)
71                  {
72                      endpoint = getEndpointForMessage(message);
73                  }
74                  else
75                  {
76                      endpoint = (OutboundEndpoint) getEndpoints().get(epCounter.next());
77                  }
78  
79                  if (endpoint == null)
80                  {
81                      logger.error("There was no matching endpoint for message part: " + part.asXML());
82                  }
83                  else
84                  {
85                      try
86                      {
87                          if (enableCorrelation != ENABLE_CORRELATION_NEVER)
88                          {
89                              boolean correlationSet = message.getCorrelationId() != null;
90                              if (!correlationSet && (enableCorrelation == ENABLE_CORRELATION_IF_NOT_SET))
91                              {
92                                  message.setCorrelationId(correlationId);
93                              }
94  
95                              // take correlation group size from the message
96                              // properties, set by concrete message splitter
97                              // implementations
98                              final int groupSize = message.getCorrelationGroupSize();
99                              message.setCorrelationGroupSize(groupSize);
100                             message.setCorrelationSequence(correlationSequence++);
101                         }
102                         if (synchronous)
103                         {
104                             result = send(session, message, endpoint);
105                         }
106                         else
107                         {
108                             dispatch(session, message, endpoint);
109                         }
110                     }
111                     catch (MuleException e)
112                     {
113                         throw new CouldNotRouteOutboundMessageException(message, endpoint, e);
114                     }
115                 }
116             }
117             return result;
118         }
119         finally
120         {
121             this.cleanup();
122         }
123     }
124 
125     /**
126      * Retrieves a specific message part for the given endpoint. the message will
127      * then be routed via the provider.
128      * 
129      * @param message the current message being processed
130      * @return the message part to dispatch
131      */
132     protected OutboundEndpoint getEndpointForMessage(MuleMessage message)
133     {
134         for (int i = 0; i < endpoints.size(); i++)
135         {
136             OutboundEndpoint endpoint = (OutboundEndpoint)endpoints.get(i);
137 
138             try
139             {
140                 if (endpoint.getFilter() == null || endpoint.getFilter().accept(message))
141                 {
142                     if (logger.isDebugEnabled())
143                     {
144                         logger.debug("Endpoint filter matched for node " + i + ". Routing message over: "
145                                      + endpoint.getEndpointURI().toString());
146                     }
147                     return endpoint;
148                 }
149                 else
150                 {
151                     if (logger.isDebugEnabled())
152                     {
153                         logger.debug("Endpoint filter did not match");
154                     }
155                 }
156             }
157             catch (Exception e)
158             {
159                 logger.error("Unable to create message for node at position " + i, e);
160                 return null;
161             }
162         }
163 
164         return null;
165     }
166 
167     public void addEndpoint(OutboundEndpoint endpoint)
168     {
169         if (endpoint.getFilter() != null && !enableEndpointFiltering)
170         {
171             throw new IllegalStateException(
172                 "Endpoints on the RoundRobin splitter router cannot have filters associated with them");
173         }
174         super.addEndpoint(endpoint);
175     }
176 
177     public boolean isEnableEndpointFiltering()
178     {
179         return enableEndpointFiltering;
180     }
181 
182     public void setEnableEndpointFiltering(boolean enableEndpointFiltering)
183     {
184         this.enableEndpointFiltering = enableEndpointFiltering;
185     }
186 
187     public boolean isDeterministic()
188     {
189         return deterministic;
190     }
191 
192     public void setDeterministic(boolean deterministic)
193     {
194         this.deterministic = deterministic;
195     }
196 
197     private class Counter
198     {
199 
200         private AtomicInteger counter;
201 
202         public Counter()
203         {
204             if (isDeterministic())
205             {
206                 counter = new AtomicInteger(0);
207             }
208             else
209             {
210                 counter = globalCounter;
211             }
212         }
213 
214         public int next()
215         {
216             return counter.getAndIncrement() % getEndpoints().size();
217         }
218 
219     }
220 
221 }