View Javadoc

1   /*
2    * $Id: AbstractOutboundRouter.java 12181 2008-06-26 20:05:55Z 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.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.ImmutableEndpoint;
18  import org.mule.api.endpoint.InvalidEndpointTypeException;
19  import org.mule.api.endpoint.OutboundEndpoint;
20  import org.mule.api.routing.MessageInfoMapping;
21  import org.mule.api.routing.OutboundRouter;
22  import org.mule.api.routing.RoutingException;
23  import org.mule.api.transaction.TransactionCallback;
24  import org.mule.api.transaction.TransactionConfig;
25  import org.mule.config.i18n.CoreMessages;
26  import org.mule.routing.AbstractRouter;
27  import org.mule.routing.MuleMessageInfoMapping;
28  import org.mule.transaction.TransactionTemplate;
29  import org.mule.util.StringMessageUtils;
30  import org.mule.util.SystemUtils;
31  
32  import java.util.Iterator;
33  import java.util.List;
34  
35  import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  /**
41   * <code>AbstractOutboundRouter</code> is a base router class that tracks
42   * statistics about message processing through the router.
43   *
44   */
45  public abstract class AbstractOutboundRouter extends AbstractRouter implements OutboundRouter
46  {
47      public static final int ENABLE_CORRELATION_IF_NOT_SET = 0;
48      public static final int ENABLE_CORRELATION_ALWAYS = 1;
49      public static final int ENABLE_CORRELATION_NEVER = 2;
50      /**
51       * logger used by this class
52       */
53      protected transient Log logger = LogFactory.getLog(getClass());
54  
55      protected List endpoints = new CopyOnWriteArrayList();
56  
57      protected String replyTo = null;
58  
59      protected int enableCorrelation = ENABLE_CORRELATION_IF_NOT_SET;
60  
61      protected MessageInfoMapping messageInfoMapping = new MuleMessageInfoMapping();
62  
63      protected TransactionConfig transactionConfig;
64  
65      public void dispatch(final MuleSession session, final MuleMessage message, final OutboundEndpoint endpoint) throws MuleException
66      {
67          setMessageProperties(session, message, endpoint);
68  
69          if (logger.isDebugEnabled())
70          {
71              try
72              {
73                  logger.debug("Message being sent to: " + endpoint.getEndpointURI() + " Message payload: \n"
74                               + StringMessageUtils.truncate(message.getPayloadAsString(), 100, false)
75                               + "\n outbound transformer is: " + endpoint.getTransformers());
76              }
77              catch (Exception e)
78              {
79                  logger.debug("Message being sent to: " + endpoint.getEndpointURI()
80                               + " Message payload: \n(unable to retrieve payload: " + e.getMessage()
81                               + "\n outbound transformer is: " + endpoint.getTransformers());
82              }
83          }
84  
85          TransactionTemplate tt = createTransactionTemplate(session, endpoint);
86          TransactionCallback cb = new TransactionCallback()
87          {
88              public Object doInTransaction() throws Exception
89              {
90                  session.dispatchEvent(message, endpoint);
91                  return null;
92              }
93          };
94          
95          try
96          {
97              tt.execute(cb);
98          }
99          catch (Exception e)
100         {
101             throw new RoutingException(message, null, e);
102         }
103         
104         
105         if (getRouterStatistics() != null)
106         {
107             if (getRouterStatistics().isEnabled())
108             {
109                 getRouterStatistics().incrementRoutedMessage(endpoint);
110             }
111         }
112     }
113 
114     public MuleMessage send(final MuleSession session, final MuleMessage message, final OutboundEndpoint endpoint) throws MuleException
115     {
116         if (replyTo != null)
117         {
118             logger.debug("event was dispatched synchronously, but there is a ReplyTo endpoint set, so using asynchronous dispatch");
119             dispatch(session, message, endpoint);
120             return null;
121         }
122 
123         this.setMessageProperties(session, message, endpoint);
124 
125         if (logger.isDebugEnabled())
126         {
127             logger.debug("Message being sent to: " + endpoint.getEndpointURI());
128             logger.debug(message);
129         }
130 
131         if (logger.isTraceEnabled())
132         {
133             try
134             {
135                 logger.trace("Message payload: \n" + message.getPayloadAsString());
136             }
137             catch (Exception e)
138             {
139                 // ignore
140             }
141         }
142 
143         TransactionTemplate tt = createTransactionTemplate(session, endpoint);
144         TransactionCallback cb = new TransactionCallback()
145         {
146             public Object doInTransaction() throws Exception
147             {
148                 return session.sendEvent(message, endpoint);
149             }
150         };
151         
152         MuleMessage result;
153         try
154         {
155             result = (MuleMessage) tt.execute(cb);
156         }
157         catch (Exception e)
158         {
159             throw new RoutingException(message, null, e);
160         }
161         
162         if (getRouterStatistics() != null)
163         {
164             if (getRouterStatistics().isEnabled())
165             {
166                 getRouterStatistics().incrementRoutedMessage(endpoint);
167             }
168         }
169 
170         if (logger.isDebugEnabled())
171         {
172             logger.debug("Response message from sending to: " + endpoint.getEndpointURI());
173             logger.debug(result);
174         }
175 
176         if (logger.isTraceEnabled())
177         {
178             try
179             {
180                 logger.trace("Message payload: \n" + result.getPayloadAsString());
181             }
182             catch (Exception e)
183             {
184                 // ignore
185             }
186         }
187 
188         return result;
189     }
190     
191     protected TransactionTemplate createTransactionTemplate(MuleSession session, ImmutableEndpoint endpoint)
192     {
193         return new TransactionTemplate(endpoint.getTransactionConfig(),
194             session.getService().getExceptionListener(), muleContext);
195     }
196 
197     protected void setMessageProperties(MuleSession session, MuleMessage message, OutboundEndpoint endpoint)
198     {
199         if (replyTo != null)
200         {
201             // if replyTo is set we'll probably want the correlationId set as
202             // well
203             message.setReplyTo(replyTo);
204             message.setProperty(MuleProperties.MULE_REPLY_TO_REQUESTOR_PROPERTY, session.getService().getName());
205             if (logger.isDebugEnabled())
206             {
207                 logger.debug("Setting replyTo=" + replyTo + " for outbound endpoint: "
208                              + endpoint.getEndpointURI());
209             }
210         }
211         if (enableCorrelation != ENABLE_CORRELATION_NEVER)
212         {
213             boolean correlationSet = message.getCorrelationId() != null;
214             if (correlationSet && (enableCorrelation == ENABLE_CORRELATION_IF_NOT_SET))
215             {
216                 if (logger.isDebugEnabled())
217                 {
218                     logger.debug("CorrelationId is already set to '" + message.getCorrelationId()
219                                  + "' , not setting it again");
220                 }
221                 return;
222             }
223             else if (correlationSet)
224             {
225                 if (logger.isDebugEnabled())
226                 {
227                     logger.debug("CorrelationId is already set to '" + message.getCorrelationId()
228                                  + "', but router is configured to overwrite it");
229                 }
230             }
231             else
232             {
233                 if (logger.isDebugEnabled())
234                 {
235                     logger.debug("No CorrelationId is set on the message, will set a new Id");
236                 }
237             }
238 
239             String correlation;
240             correlation = messageInfoMapping.getCorrelationId(message);
241             if (logger.isDebugEnabled())
242             {
243                 logger.debug("Extracted correlation Id as: " + correlation);
244             }
245 
246             if (logger.isDebugEnabled())
247             {
248                 StringBuffer buf = new StringBuffer();
249                 buf.append("Setting Correlation info on Outbound router for endpoint: ").append(
250                     endpoint.getEndpointURI());
251                 buf.append(SystemUtils.LINE_SEPARATOR).append("Id=").append(correlation);
252                 // buf.append(", ").append("Seq=").append(seq);
253                 // buf.append(", ").append("Group Size=").append(group);
254                 logger.debug(buf.toString());
255             }
256             message.setCorrelationId(correlation);
257             // message.setCorrelationGroupSize(group);
258             // message.setCorrelationSequence(seq);
259         }
260     }
261 
262     public List getEndpoints()
263     {
264         return endpoints;
265     }
266 
267     public void setEndpoints(List endpoints)
268     {
269         this.endpoints.clear();
270         // this.endpoints = new CopyOnWriteArrayList(endpoints);
271         // Ensure all endpoints are outbound endpoints
272         // This will go when we start dropping support for 1.4 and start using 1.5
273         for (Iterator iterator = endpoints.iterator(); iterator.hasNext();)
274         {
275             ImmutableEndpoint umoEndpoint = (ImmutableEndpoint) iterator.next();
276             if (!(umoEndpoint instanceof OutboundEndpoint))
277             {
278                 throw new InvalidEndpointTypeException(CoreMessages.outboundRouterMustUseOutboudEndpoints(
279                     this, umoEndpoint));
280             }
281             else
282             {
283                 addEndpoint((OutboundEndpoint) umoEndpoint);
284             }
285         }
286     }
287 
288     public void addEndpoint(OutboundEndpoint endpoint)
289     {
290         endpoints.add(endpoint);
291     }
292 
293     public boolean removeEndpoint(OutboundEndpoint endpoint)
294     {
295         return endpoints.remove(endpoint);
296     }
297 
298     public String getReplyTo()
299     {
300         return replyTo;
301     }
302 
303     public void setReplyTo(String replyTo)
304     {
305         this.replyTo = replyTo;
306     }
307 
308     public int getEnableCorrelation()
309     {
310         return enableCorrelation;
311     }
312 
313     public void setEnableCorrelation(int enableCorrelation)
314     {
315         this.enableCorrelation = enableCorrelation;
316     }
317 
318     public void setEnableCorrelationAsString(String enableCorrelation)
319     {
320         if (enableCorrelation != null)
321         {
322             if (enableCorrelation.equals("ALWAYS"))
323             {
324                 this.enableCorrelation = ENABLE_CORRELATION_ALWAYS;
325             }
326             else if (enableCorrelation.equals("NEVER"))
327             {
328                 this.enableCorrelation = ENABLE_CORRELATION_NEVER;
329             }
330             else if (enableCorrelation.equals("IF_NOT_SET"))
331             {
332                 this.enableCorrelation = ENABLE_CORRELATION_IF_NOT_SET;
333             }
334             else
335             {
336                 throw new IllegalArgumentException("Value for enableCorrelation not recognised: "
337                                                    + enableCorrelation);
338             }
339         }
340     }
341 
342     public MessageInfoMapping getMessageInfoMapping()
343     {
344         return messageInfoMapping;
345     }
346 
347     public void setMessageInfoMapping(MessageInfoMapping messageInfoMapping)
348     {
349         this.messageInfoMapping = messageInfoMapping;
350     }
351 
352     public TransactionConfig getTransactionConfig()
353     {
354         return transactionConfig;
355     }
356 
357     public void setTransactionConfig(TransactionConfig transactionConfig)
358     {
359         this.transactionConfig = transactionConfig;
360     }
361 
362     public boolean isDynamicEndpoints()
363     {
364         return false;
365     }
366 
367     /**
368      * @param name the Endpoint identifier
369      * @return the Endpoint or null if the endpointUri is not registered
370      * @see org.mule.api.routing.InboundRouterCollection
371      */
372     public OutboundEndpoint getEndpoint(String name)
373     {
374         OutboundEndpoint endpointDescriptor;
375         for (Iterator iterator = endpoints.iterator(); iterator.hasNext();)
376         {
377             endpointDescriptor = (OutboundEndpoint) iterator.next();
378             if (endpointDescriptor.getName().equals(name))
379             {
380                 return endpointDescriptor;
381             }
382         }
383         return null;
384     }
385 }