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