View Javadoc

1   /*
2    * $Id: AbstractMessageDispatcher.java 19191 2010-08-25 21:05:23Z tcarlson $
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 AbstractConnectable 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 = (String) event.getMessage().getProperty(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              if (endpoint.getExchangePattern().hasResponse())
74              {
75                  MuleMessage resultMessage = doSend(event);
76                  if (resultMessage != null)
77                  {
78                      resultEvent = new DefaultMuleEvent(resultMessage, event);
79                      // TODO It seems like this should go here but it causes unwanted behaviour and breaks test cases.
80                      //if (!disableTransportTransformer)
81                      //{
82                      //    applyResponseTransformers(resultEvent);            
83                      //}
84                  }
85              }
86              else
87              {
88                  doDispatch(event);
89              }
90          }
91          catch (MuleException muleException)
92          {
93              throw muleException;
94          }
95          catch (Exception e)
96          {
97              throw new DispatchException(event, (OutboundEndpoint) endpoint, e);
98          }
99          return resultEvent;
100     }
101 
102     /**
103      * @deprecated
104      */
105     @Deprecated
106     protected boolean returnResponse(MuleEvent event)
107     {
108         // Pass through false to conserve the existing behavior of this method but
109         // avoid duplication of code.
110         return returnResponse(event, false);
111     }
112 
113     /**
114      * Used to determine if the dispatcher implementation should wait for a response
115      * to an event on a response channel after it sends the event. The following
116      * rules apply:
117      * <ol>
118      * <li>The connector has to support "back-channel" response. Some transports do
119      * not have the notion of a response channel.
120      * <li>Check if the endpoint is synchronous (outbound synchronicity is not
121      * explicit since 2.2 and does not use the remoteSync message property).
122      * <li>Or, if the send() method on the dispatcher was used. (This is required
123      * because the ChainingRouter uses send() with async endpoints. See MULE-4631).
124      * <li>Finally, if the current service has a response router configured, that the
125      * router will handle the response channel event and we should not try and
126      * receive a response in the Message dispatcher If remotesync should not be used
127      * we must remove the REMOTE_SYNC header Note the MuleClient will automatically
128      * set the REMOTE_SYNC header when client.send(..) is called so that results are
129      * returned from remote invocations too.
130      * </ol>
131      * 
132      * @param event the current event
133      * @return true if a response channel should be used to get a response from the
134      *         event dispatch.
135      */
136     protected boolean returnResponse(MuleEvent event, boolean doSend)
137     {
138         boolean remoteSync = false;
139         if (event.getEndpoint().getConnector().isResponseEnabled())
140         {
141             boolean hasResponse = event.getEndpoint().getExchangePattern().hasResponse();
142             remoteSync = hasResponse || doSend;
143             if (remoteSync)
144             {
145                 // service will be null for client calls
146                 if (event.getFlowConstruct() != null && event.getFlowConstruct() instanceof Service)
147                 {
148                     ServiceAsyncReplyCompositeMessageSource responseRouters = ((Service) event.getFlowConstruct()).getAsyncReplyMessageSource();
149                     if (responseRouters != null && responseRouters.getEndpoints().size() > 0)
150                     {
151                         remoteSync = false;
152                     }
153                     else
154                     {
155                         remoteSync = true;
156                     }
157                 }
158             }
159         }
160         if (!remoteSync)
161         {
162             event.getMessage().removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
163         }
164         return remoteSync;
165     }
166 
167     @Override
168     protected WorkManager getWorkManager()
169     {
170         try
171         {
172             return connector.getDispatcherWorkManager();
173         }
174         catch (MuleException e)
175         {
176             logger.error(e);
177             return null;
178         }
179     }
180 
181     @Override
182     public OutboundEndpoint getEndpoint()
183     {
184         return (OutboundEndpoint) super.getEndpoint();
185     }
186     
187     protected void applyOutboundTransformers(MuleEvent event) throws MuleException
188     {
189         event.getMessage().applyTransformers(event, defaultOutboundTransformers);
190     }
191 
192     protected void applyResponseTransformers(MuleEvent event) throws MuleException
193     {
194         event.getMessage().applyTransformers(event, defaultResponseTransformers);
195     }
196 
197     protected abstract void doDispatch(MuleEvent event) throws Exception;
198 
199     protected abstract MuleMessage doSend(MuleEvent event) throws Exception;
200 }