View Javadoc

1   /*
2    * $Id: AbstractMessageDispatcher.java 12247 2008-07-07 21:25:01Z dfeist $
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.transport;
12  
13  import org.mule.OptimizedRequestContext;
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.config.MuleProperties;
19  import org.mule.api.endpoint.ImmutableEndpoint;
20  import org.mule.api.endpoint.OutboundEndpoint;
21  import org.mule.api.routing.ResponseRouterCollection;
22  import org.mule.api.transaction.Transaction;
23  import org.mule.api.transaction.TransactionException;
24  import org.mule.api.transport.DispatchException;
25  import org.mule.api.transport.MessageDispatcher;
26  import org.mule.context.notification.EndpointMessageNotification;
27  import org.mule.context.notification.SecurityNotification;
28  import org.mule.transaction.TransactionCoordination;
29  
30  import javax.resource.spi.work.Work;
31  import javax.resource.spi.work.WorkManager;
32  
33  /**
34   * Provide a default dispatch (client) support for handling threads lifecycle and validation.
35   */
36  public abstract class AbstractMessageDispatcher extends AbstractConnectable implements MessageDispatcher
37  {
38  
39      public AbstractMessageDispatcher(OutboundEndpoint endpoint)
40      {
41          super(endpoint);
42      }
43  
44      /*
45       * (non-Javadoc)
46       * 
47       * @see org.mule.api.transport.MessageDispatcher#dispatch(org.mule.api.MuleEvent)
48       */
49      public final void dispatch(MuleEvent event) throws DispatchException
50      {
51          event.setSynchronous(false);
52          event.getMessage().setProperty(MuleProperties.MULE_ENDPOINT_PROPERTY,
53              event.getEndpoint().getEndpointURI().toString());
54          event = OptimizedRequestContext.criticalSetEvent(event); // MULE-2112
55  
56          // Apply Security filter if one is set
57          ImmutableEndpoint endpoint = event.getEndpoint();
58          if (endpoint.getSecurityFilter() != null)
59          {
60              try
61              {
62                  endpoint.getSecurityFilter().authenticate(event);
63              }
64              catch (org.mule.api.security.SecurityException e)
65              {
66                  // TODO MULE-863: Do we need this warning?
67                  logger.warn("Outbound Request was made but was not authenticated: " + e.getMessage(), e);
68                  connector.fireNotification(new SecurityNotification(e,
69                      SecurityNotification.SECURITY_AUTHENTICATION_FAILED));
70                  connector.handleException(e);
71                  return;
72              }
73              catch (MuleException e)
74              {
75                  disposeAndLogException();
76                  throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
77              }
78          }
79  
80          try
81          {
82              Transaction tx = TransactionCoordination.getInstance().getTransaction();
83              if (isDoThreading() && !event.isSynchronous() && tx == null)
84              {
85                  connector.getDispatcherWorkManager().scheduleWork(new Worker(event), WorkManager.INDEFINITE, null, connector);
86              }
87              else
88              {
89                  // Make sure we are connected
90                  connectionStrategy.connect(this);
91                  doDispatch(event);
92                  if (connector.isEnableMessageEvents())
93                  {
94                      String component = null;
95                      if (event.getService() != null)
96                      {
97                          component = event.getService().getName();
98                      }
99                      connector.fireNotification(new EndpointMessageNotification(event.getMessage(), event
100                         .getEndpoint(), component, EndpointMessageNotification.MESSAGE_DISPATCHED));
101                 }
102             }
103         }
104         catch (DispatchException e)
105         {
106             disposeAndLogException();
107             throw e;
108         }
109         catch (Exception e)
110         {
111             disposeAndLogException();
112             throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
113         }
114     }
115 
116     public final MuleMessage send(MuleEvent event) throws DispatchException
117     {
118         // No point continuing if the service has rolledback the transaction
119         if (isTransactionRollback())
120         {
121             return event.getMessage();
122         }
123 
124         event.setSynchronous(true);
125         event.getMessage().setProperty(MuleProperties.MULE_ENDPOINT_PROPERTY,
126             event.getEndpoint().getEndpointURI().getUri().toString());
127         event = OptimizedRequestContext.unsafeSetEvent(event);
128 
129         // Apply Security filter if one is set
130         ImmutableEndpoint endpoint = event.getEndpoint();
131         if (endpoint.getSecurityFilter() != null)
132         {
133             try
134             {
135                 endpoint.getSecurityFilter().authenticate(event);
136             }
137             catch (org.mule.api.security.SecurityException e)
138             {
139                 logger.warn("Outbound Request was made but was not authenticated: " + e.getMessage(), e);
140                 connector.fireNotification(new SecurityNotification(e,
141                     SecurityNotification.SECURITY_AUTHENTICATION_FAILED));
142                 connector.handleException(e);
143                 return event.getMessage();
144             }
145             catch (MuleException e)
146             {
147                 disposeAndLogException();
148                 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
149             }
150         }
151 
152         try
153         {
154             // Make sure we are connected
155             connectionStrategy.connect(this);
156 
157             MuleMessage result = doSend(event);
158             if (connector.isEnableMessageEvents())
159             {
160                 String component = null;
161                 if (event.getService() != null)
162                 {
163                     component = event.getService().getName();
164                 }
165                 connector.fireNotification(new EndpointMessageNotification(event.getMessage(), event.getEndpoint(),
166                     component, EndpointMessageNotification.MESSAGE_SENT));
167             }
168 
169             //TODO: This chunk can be removed since there is no need to remove any properites since they are now scoped
170             // Once a dispatcher has done its work we need to remove this property
171             // so that it is not propagated to the next request
172 //            if (result != null
173 //                    && result.getPropertyNames().contains(MuleProperties.MULE_REMOTE_SYNC_PROPERTY))
174             //{
175 //                result = RequestContext.safeMessageCopy(result);
176             //    result.removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
177             //}
178             return result;
179         }
180         catch (DispatchException e)
181         {
182             disposeAndLogException();
183             throw e;
184         }
185         catch (Exception e)
186         {
187             disposeAndLogException();
188             throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
189         }
190     }
191 
192     /**
193      * RemoteSync causes the message dispatch to wait for a response to an event on a
194      * response channel after it sends the event. The following rules apply to
195      * RemoteSync 1. The connector has to support remoteSync. Some transports do not
196      * have the notion of a response channel 2. Check if the endpoint has been
197      * configured for remoteSync 3. Check if the REMOTE_SYNC message header has been
198      * set 4. Finally, if the current service has a response router configured,
199      * that the router will handle the response channel event and we should not try
200      * and receive a response in the Message dispatcher If remotesync should not be
201      * used we must remove the REMOTE_SYNC header Note the MuleClient will
202      * automatically set the REMOTE_SYNC header when client.send(..) is called so
203      * that results are returned from remote invocations too.
204      *
205      * @param event the current event
206      * @return true if a response channel should be used to get a resposne from the
207      *         event dispatch.
208      */
209     protected boolean useRemoteSync(MuleEvent event)
210     {
211         boolean remoteSync = false;
212         if (event.getEndpoint().getConnector().isRemoteSyncEnabled())
213         {
214             remoteSync = event.getEndpoint().isRemoteSync()
215                             || event.getMessage().getBooleanProperty(
216                                 MuleProperties.MULE_REMOTE_SYNC_PROPERTY, false);
217             if (remoteSync)
218             {
219                 // service will be null for client calls
220                 if (event.getService() != null)
221                 {
222                     ResponseRouterCollection responseRouters = event.getService().getResponseRouter();
223                     if (responseRouters != null && responseRouters.hasEndpoints())
224                     {
225                         remoteSync = false;
226                     }
227                     else
228                     {
229                         remoteSync = true;
230                     }
231                 }
232             }
233         }
234         if (!remoteSync)
235         {
236             event.getMessage().removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
237         }
238         return remoteSync;
239     }
240 
241     private class Worker implements Work
242     {
243         private MuleEvent event;
244 
245         public Worker(MuleEvent event)
246         {
247             this.event = event;
248         }
249 
250         /*
251          * (non-Javadoc)
252          * 
253          * @see java.lang.Runnable#run()
254          */
255         public void run()
256         {
257             try
258             {
259                 event = RequestContext.setEvent(event);
260                 // Make sure we are connected
261                 connectionStrategy.connect(AbstractMessageDispatcher.this);
262                 AbstractMessageDispatcher.this.doDispatch(event);
263 
264                 if (connector.isEnableMessageEvents())
265                 {
266                     String component = null;
267                     if (event.getService() != null)
268                     {
269                         component = event.getService().getName();
270                     }
271 
272                     connector.fireNotification(new EndpointMessageNotification(event.getMessage(), event
273                         .getEndpoint(), component, EndpointMessageNotification.MESSAGE_DISPATCHED));
274                 }
275             }
276             catch (Exception e)
277             {
278                 AbstractMessageDispatcher.this.getConnector().handleException(e);
279             }
280         }
281 
282         public void release()
283         {
284             // nothing to do
285         }
286     }
287 
288     /**
289      * Checks to see if the current transaction has been rolled back
290      * 
291      * @return
292      */
293     protected boolean isTransactionRollback()
294     {
295         try
296         {
297             Transaction tx = TransactionCoordination.getInstance().getTransaction();
298             if (tx != null && tx.isRollbackOnly())
299             {
300                 return true;
301             }
302         }
303         catch (TransactionException e)
304         {
305             // TODO MULE-863: What should we really do?
306             logger.warn(e.getMessage());
307         }
308         return false;
309     }
310 
311     protected abstract void doDispatch(MuleEvent event) throws Exception;
312 
313     protected abstract MuleMessage doSend(MuleEvent event) throws Exception;
314                                              
315 }