View Javadoc

1   /*
2    * $Id: AbstractMessageDispatcher.java 20477 2010-12-06 23:38:52Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.transport;
12  
13  import org.mule.DefaultMuleEvent;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleException;
16  import org.mule.api.MuleMessage;
17  import org.mule.api.config.MuleProperties;
18  import org.mule.api.context.WorkManager;
19  import org.mule.api.endpoint.OutboundEndpoint;
20  import org.mule.api.service.Service;
21  import org.mule.api.transformer.Transformer;
22  import org.mule.api.transport.DispatchException;
23  import org.mule.api.transport.MessageDispatcher;
24  import org.mule.service.ServiceAsyncReplyCompositeMessageSource;
25  
26  import java.util.List;
27  
28  /**
29   * Abstract implementation of an outbound channel adaptors. Outbound channel adaptors
30   * send messages over over a specific transport. Different implementations may
31   * support different Message Exchange Patterns.
32   */
33  public abstract class AbstractMessageDispatcher extends AbstractTransportMessageHandler implements MessageDispatcher
34  {
35  
36      protected List<Transformer> defaultOutboundTransformers;
37      protected List<Transformer> defaultResponseTransformers;
38  
39      public AbstractMessageDispatcher(OutboundEndpoint endpoint)
40      {
41          super(endpoint);
42      }
43  
44      @Override
45      protected ConnectableLifecycleManager createLifecycleManager()
46      {
47          defaultOutboundTransformers = connector.getDefaultOutboundTransformers(endpoint);       
48          defaultResponseTransformers = connector.getDefaultResponseTransformers(endpoint);       
49          return new ConnectableLifecycleManager<MessageDispatcher>(getDispatcherName(), this);
50      }
51  
52      protected String getDispatcherName()
53      {
54          return getConnector().getName() + ".dispatcher." + System.identityHashCode(this);
55      }
56      
57  
58  
59      public MuleEvent process(MuleEvent event) throws MuleException
60      {
61          MuleEvent resultEvent = null;
62          try
63          {
64              connect();
65  
66              String prop = event.getMessage().getOutboundProperty(MuleProperties.MULE_DISABLE_TRANSPORT_TRANSFORMER_PROPERTY);
67              boolean disableTransportTransformer = (prop != null && Boolean.parseBoolean(prop)) || endpoint.isDisableTransportTransformer();
68                          
69              if (!disableTransportTransformer)
70              {
71                  applyOutboundTransformers(event);            
72              }
73              // TODO this is the same logic as in OptionalAsyncInterceptingMessageProcessor.  Better to have it in one place
74              Object forceSyncPropertyValue = event.getMessage().getInboundProperty(MuleProperties.MULE_FORCE_SYNC_PROPERTY);
75              boolean forceSync = Boolean.TRUE.equals(forceSyncPropertyValue);
76              boolean hasResponse = endpoint.getExchangePattern().hasResponse();
77              boolean isTransacted = endpoint.getTransactionConfig().isTransacted();
78              if (forceSync || hasResponse || isTransacted)            
79              {
80                  MuleMessage resultMessage = doSend(event);
81                  if (hasResponse && resultMessage != null)
82                  {
83                      resultEvent = new DefaultMuleEvent(resultMessage, event);
84                      // TODO It seems like this should go here but it causes unwanted behaviour and breaks test cases.
85                      //if (!disableTransportTransformer)
86                      //{
87                      //    applyResponseTransformers(resultEvent);            
88                      //}
89                  }
90              }
91              else
92              {
93                  doDispatch(event);
94              }
95          }
96          catch (MuleException muleException)
97          {
98              throw muleException;
99          }
100         catch (Exception e)
101         {
102             throw new DispatchException(event, (OutboundEndpoint) endpoint, e);
103         }
104         return resultEvent;
105     }
106 
107     /**
108      * @deprecated
109      */
110     @Deprecated
111     protected boolean returnResponse(MuleEvent event)
112     {
113         // Pass through false to conserve the existing behavior of this method but
114         // avoid duplication of code.
115         return returnResponse(event, false);
116     }
117 
118     /**
119      * Used to determine if the dispatcher implementation should wait for a response
120      * to an event on a response channel after it sends the event. The following
121      * rules apply:
122      * <ol>
123      * <li>The connector has to support "back-channel" response. Some transports do
124      * not have the notion of a response channel.
125      * <li>Check if the endpoint is synchronous (outbound synchronicity is not
126      * explicit since 2.2 and does not use the remoteSync message property).
127      * <li>Or, if the send() method on the dispatcher was used. (This is required
128      * because the ChainingRouter uses send() with async endpoints. See MULE-4631).
129      * <li>Finally, if the current service has a response router configured, that the
130      * router will handle the response channel event and we should not try and
131      * receive a response in the Message dispatcher If remotesync should not be used
132      * we must remove the REMOTE_SYNC header Note the MuleClient will automatically
133      * set the REMOTE_SYNC header when client.send(..) is called so that results are
134      * returned from remote invocations too.
135      * </ol>
136      * 
137      * @param event the current event
138      * @return true if a response channel should be used to get a response from the
139      *         event dispatch.
140      */
141     protected boolean returnResponse(MuleEvent event, boolean doSend)
142     {
143         boolean remoteSync = false;
144         if (event.getEndpoint().getConnector().isResponseEnabled())
145         {
146             boolean hasResponse = event.getEndpoint().getExchangePattern().hasResponse();
147             remoteSync = hasResponse || doSend;
148             if (remoteSync)
149             {
150                 // service will be null for client calls
151                 if (event.getFlowConstruct() != null && event.getFlowConstruct() instanceof Service)
152                 {
153                     ServiceAsyncReplyCompositeMessageSource responseRouters = ((Service) event.getFlowConstruct()).getAsyncReplyMessageSource();
154                     if (responseRouters != null && responseRouters.getEndpoints().size() > 0)
155                     {
156                         remoteSync = false;
157                     }
158                     else
159                     {
160                         remoteSync = true;
161                     }
162                 }
163             }
164         }
165         if (!remoteSync)
166         {
167             event.getMessage().removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
168         }
169         return remoteSync;
170     }
171 
172     @Override
173     protected WorkManager getWorkManager()
174     {
175         try
176         {
177             return connector.getDispatcherWorkManager();
178         }
179         catch (MuleException e)
180         {
181             logger.error(e);
182             return null;
183         }
184     }
185 
186     @Override
187     public OutboundEndpoint getEndpoint()
188     {
189         return (OutboundEndpoint) super.getEndpoint();
190     }
191     
192     protected void applyOutboundTransformers(MuleEvent event) throws MuleException
193     {
194         event.getMessage().applyTransformers(event, defaultOutboundTransformers);
195     }
196 
197     protected void applyResponseTransformers(MuleEvent event) throws MuleException
198     {
199         event.getMessage().applyTransformers(event, defaultResponseTransformers);
200     }
201 
202     protected abstract void doDispatch(MuleEvent event) throws Exception;
203 
204     protected abstract MuleMessage doSend(MuleEvent event) throws Exception;
205 }