View Javadoc

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