View Javadoc

1   /*
2    * $Id: AbstractMessageReceiver.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.MessageExchangePattern;
15  import org.mule.OptimizedRequestContext;
16  import org.mule.ResponseOutputStream;
17  import org.mule.api.MuleEvent;
18  import org.mule.api.MuleException;
19  import org.mule.api.MuleMessage;
20  import org.mule.api.MuleSession;
21  import org.mule.api.config.MuleProperties;
22  import org.mule.api.construct.FlowConstruct;
23  import org.mule.api.context.WorkManager;
24  import org.mule.api.endpoint.EndpointURI;
25  import org.mule.api.endpoint.InboundEndpoint;
26  import org.mule.api.lifecycle.CreateException;
27  import org.mule.api.lifecycle.InitialisationException;
28  import org.mule.api.processor.MessageProcessor;
29  import org.mule.api.routing.filter.FilterUnacceptedException;
30  import org.mule.api.transaction.Transaction;
31  import org.mule.api.transformer.Transformer;
32  import org.mule.api.transport.Connector;
33  import org.mule.api.transport.MessageReceiver;
34  import org.mule.api.transport.PropertyScope;
35  import org.mule.api.transport.ReplyToHandler;
36  import org.mule.context.notification.EndpointMessageNotification;
37  import org.mule.session.DefaultMuleSession;
38  import org.mule.session.LegacySessionHandler;
39  import org.mule.transaction.TransactionCoordination;
40  import org.mule.util.ClassUtils;
41  import org.mule.util.ObjectUtils;
42  
43  import java.io.OutputStream;
44  import java.util.List;
45  
46  import org.apache.commons.lang.SerializationException;
47  
48  /**
49   * <code>AbstractMessageReceiver</code> provides common methods for all Message
50   * Receivers provided with Mule. A message receiver enables an endpoint to receive a
51   * message from an external system.
52   */
53  public abstract class AbstractMessageReceiver extends AbstractTransportMessageHandler implements MessageReceiver
54  {
55      /**
56       * The Service with which this receiver is associated with
57       */
58      protected FlowConstruct flowConstruct;
59  
60      /**
61       * {@link MessageProcessor} chain used to process messages once the transport
62       * specific {@link MessageReceiver} has received transport message and created
63       * the {@link MuleEvent}
64       */
65      protected MessageProcessor listener;
66  
67      /**
68       * Stores the key to this receiver, as used by the Connector to store the
69       * receiver.
70       */
71      protected String receiverKey = null;
72  
73      /**
74       * Stores the endpointUri that this receiver listens on. This enpoint can be
75       * different to the endpointUri in the endpoint stored on the receiver as
76       * endpoint endpointUri may get rewritten if this endpointUri is a wildcard
77       * endpointUri such as jms.*
78       */
79      private EndpointURI endpointUri;
80  
81      protected List<Transformer> defaultInboundTransformers;
82      protected List<Transformer> defaultResponseTransformers;
83      
84      protected ReplyToHandler replyToHandler;
85  
86      /**
87       * Creates the Message Receiver
88       *
89       * @param connector the endpoint that created this listener
90       * @param flowConstruct the flow construct to associate with the receiver.
91       * @param endpoint the provider contains the endpointUri on which the receiver
92       *            will listen on. The endpointUri can be anything and is specific to
93       *            the receiver implementation i.e. an email address, a directory, a
94       *            jms destination or port address.
95       * @see FlowConstruct
96       * @see InboundEndpoint
97       */
98      public AbstractMessageReceiver(Connector connector, FlowConstruct flowConstruct, InboundEndpoint endpoint)
99          throws CreateException
100     {
101         super(endpoint);
102 
103         if (flowConstruct == null)
104         {
105             throw new IllegalArgumentException("FlowConstruct cannot be null");
106         }
107         this.flowConstruct = flowConstruct;
108     }
109 
110     @Override
111     protected ConnectableLifecycleManager createLifecycleManager()
112     {
113         return new ConnectableLifecycleManager<MessageReceiver>(getReceiverKey(), this);
114     }
115 
116     /**
117      * Method used to perform any initialisation work. If a fatal error occurs during
118      * initialisation an <code>InitialisationException</code> should be thrown,
119      * causing the Mule instance to shutdown. If the error is recoverable, say by
120      * retrying to connect, a <code>RecoverableException</code> should be thrown.
121      * There is no guarantee that by throwing a Recoverable exception that the Mule
122      * instance will not shut down.
123      *
124      * @throws org.mule.api.lifecycle.InitialisationException if a fatal error occurs
125      *             causing the Mule instance to shutdown
126      * @throws org.mule.api.lifecycle.RecoverableException if an error occurs that
127      *             can be recovered from
128      */
129     @Override
130     public final void initialise() throws InitialisationException
131     {
132         endpointUri = endpoint.getEndpointURI();
133 
134         defaultInboundTransformers = connector.getDefaultInboundTransformers(endpoint);
135         defaultResponseTransformers = connector.getDefaultResponseTransformers(endpoint);
136 
137         replyToHandler = getReplyToHandler();
138         
139         super.initialise();
140     }
141 
142     public FlowConstruct getFlowConstruct()
143     {
144         return flowConstruct;
145     }
146 
147     public final MuleEvent routeMessage(MuleMessage message) throws MuleException
148     {
149         Transaction tx = TransactionCoordination.getInstance().getTransaction();
150         return routeMessage(message, tx, null);
151     }
152 
153     public final MuleEvent routeMessage(MuleMessage message, Transaction trans)
154         throws MuleException
155     {
156         return routeMessage(message, trans, null);
157     }
158 
159     public final MuleEvent routeMessage(MuleMessage message,
160                                           Transaction trans,
161                                           OutputStream outputStream) throws MuleException
162     {
163         return routeMessage(message, new DefaultMuleSession(connector.getMuleContext()), trans,
164             outputStream);
165     }
166 
167     public final MuleEvent routeMessage(MuleMessage message,
168                                           MuleSession session,
169                                           Transaction trans,
170                                           OutputStream outputStream) throws MuleException
171     {
172 
173         final Object o = message.getInboundProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
174         if (ObjectUtils.getBoolean(o, false) && !endpoint.getExchangePattern().hasResponse())
175         {
176             logger.warn("MuleClient.send() was used but inbound endpoint "
177                         + endpoint.getEndpointURI().getUri().toString()
178                         + " is not 'request-response'.  No response will be returned.");
179         }
180 
181         message.removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, PropertyScope.INBOUND);
182         String rootId = message.getInboundProperty(MuleProperties.MULE_ROOT_MESSAGE_ID_PROPERTY);
183         if (rootId != null)
184         {
185             message.setMessageRootId(rootId);
186             message.removeProperty(MuleProperties.MULE_ROOT_MESSAGE_ID_PROPERTY, PropertyScope.INBOUND);
187         }
188         MuleEvent muleEvent = createMuleEvent(message, outputStream);
189         muleEvent = OptimizedRequestContext.unsafeSetEvent(muleEvent);
190 
191         if (!endpoint.isDisableTransportTransformer())
192         {
193             applyInboundTransformers(muleEvent);
194         }
195         MuleEvent resultEvent = listener.process(muleEvent);
196         if (resultEvent != null && resultEvent.getMessage() != null
197             && resultEvent.getMessage().getExceptionPayload() != null
198             && resultEvent.getMessage().getExceptionPayload().getException() instanceof FilterUnacceptedException)
199         {
200             handleUnacceptedFilter(muleEvent.getMessage());
201             return muleEvent;
202         }
203 
204         if (resultEvent != null)
205         {
206             // Do  not propagate security context back to caller
207             MuleSession resultSession = new DefaultMuleSession(resultEvent.getSession(), resultEvent.getMuleContext());
208             resultSession.setSecurityContext(null);
209             connector.getSessionHandler().storeSessionInfoToMessage(resultSession, resultEvent.getMessage());
210         }
211 
212         if (endpoint.getExchangePattern()== MessageExchangePattern.REQUEST_RESPONSE && resultEvent != null && resultEvent.getMessage() != null && !endpoint.isDisableTransportTransformer())
213         {
214             applyResponseTransformers(resultEvent);
215         }
216 
217         if (connector.isEnableMessageEvents() && endpoint.getExchangePattern().hasResponse() && resultEvent != null)
218         {
219             connector.fireNotification(new EndpointMessageNotification(
220                     resultEvent.getMessage(), endpoint, resultEvent
221                             .getFlowConstruct(),
222                     EndpointMessageNotification.MESSAGE_RESPONSE));
223         }
224 
225         return resultEvent;
226     }
227 
228     protected void applyInboundTransformers(MuleEvent event) throws MuleException
229     {
230         event.getMessage().applyTransformers(event, defaultInboundTransformers);
231     }
232 
233     protected void applyResponseTransformers(MuleEvent event) throws MuleException
234     {
235         event.getMessage().applyTransformers(event, defaultResponseTransformers);
236     }
237 
238     protected MuleMessage handleUnacceptedFilter(MuleMessage message)
239     {
240         if (logger.isDebugEnabled())
241         {
242             String messageId;
243             messageId = message.getUniqueId();
244             logger.debug("Message " + messageId + " failed to pass filter on endpoint: " + endpoint
245                          + ". Message is being ignored");
246         }
247         return message;
248     }
249 
250     protected MuleEvent createMuleEvent(MuleMessage message, OutputStream outputStream)
251         throws MuleException
252     {
253         ResponseOutputStream ros = null;
254         if (outputStream != null)
255         {
256             if (outputStream instanceof ResponseOutputStream)
257             {
258                 ros = (ResponseOutputStream) outputStream;
259             }
260             else
261             {
262                 ros = new ResponseOutputStream(outputStream);
263             }
264         }
265         MuleSession session;
266         try
267         {
268             session = connector.getSessionHandler().retrieveSessionInfoFromMessage(message);
269         }
270         catch (SerializationException se)
271         {
272             try
273             {
274                 // EE-1820 Support message headers generated by previous Mule versions
275                 session = new LegacySessionHandler().retrieveSessionInfoFromMessage(message);
276             }
277             catch (Exception e)
278             {
279                 // If the LegacySessionHandler didn't work either, just bubble up the original SerializationException (see MULE-5487)  
280                 throw se;
281             }
282         }
283         if (session != null)
284         {
285             session.setFlowConstruct(flowConstruct);
286         }
287         else
288         {
289             session = new DefaultMuleSession(flowConstruct, connector.getMuleContext());
290         }
291         if (message.getReplyTo() != null)
292         {
293             return new DefaultMuleEvent(message, getEndpoint(),session, replyToHandler, ros);
294 
295         }
296         else
297         {
298             return new DefaultMuleEvent(message, getEndpoint(), session, null, ros);
299         }
300     }
301 
302     public EndpointURI getEndpointURI()
303     {
304         return endpointUri;
305     }
306 
307     @Override
308     public String getConnectionDescription()
309     {
310         return endpoint.getEndpointURI().toString();
311     }
312 
313     protected String getConnectEventId()
314     {
315         return connector.getName() + ".receiver (" + endpoint.getEndpointURI() + ")";
316     }
317 
318     // TODO MULE-4871 Receiver key should not be mutable
319     public void setReceiverKey(String receiverKey)
320     {
321         this.receiverKey = receiverKey;
322     }
323 
324     public String getReceiverKey()
325     {
326         return receiverKey;
327     }
328 
329     @Override
330     public InboundEndpoint getEndpoint()
331     {
332         return (InboundEndpoint) super.getEndpoint();
333     }
334 
335     // TODO MULE-4871 Endpoint should not be mutable
336     public void setEndpoint(InboundEndpoint endpoint)
337     {
338         super.setEndpoint(endpoint);
339     }
340 
341     @Override
342     protected WorkManager getWorkManager()
343     {
344         try
345         {
346             return connector.getReceiverWorkManager();
347         }
348         catch (MuleException e)
349         {
350             logger.error(e);
351             return null;
352         }
353     }
354 
355     @Override
356     public String toString()
357     {
358         final StringBuffer sb = new StringBuffer(80);
359         sb.append(ClassUtils.getSimpleName(this.getClass()));
360         sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
361         sb.append(", receiverKey=").append(receiverKey);
362         sb.append(", endpoint=").append(endpoint.getEndpointURI());
363         sb.append('}');
364         return sb.toString();
365     }
366 
367     public void setListener(MessageProcessor processor)
368     {
369         this.listener = processor;
370     }
371 
372     @Override
373     protected void doDispose()
374     {
375         this.listener = null;
376         this.flowConstruct = null;
377         super.doDispose();
378     }
379     
380     protected ReplyToHandler getReplyToHandler()
381     {
382         return ((AbstractConnector) endpoint.getConnector()).getReplyToHandler(endpoint);
383     }
384 }