View Javadoc

1   /*
2    * $Id: AbstractMessageReceiver.java 20358 2010-11-26 20:15:18Z 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.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.context.notification.EndpointMessageNotification;
36  import org.mule.session.DefaultMuleSession;
37  import org.mule.session.LegacySessionHandler;
38  import org.mule.transaction.TransactionCoordination;
39  import org.mule.util.ClassUtils;
40  import org.mule.util.ObjectUtils;
41  
42  import java.io.OutputStream;
43  import java.util.List;
44  
45  import org.apache.commons.lang.SerializationException;
46  
47  /**
48   * <code>AbstractMessageReceiver</code> provides common methods for all Message
49   * Receivers provided with Mule. A message receiver enables an endpoint to receive a
50   * message from an external system.
51   */
52  public abstract class AbstractMessageReceiver extends AbstractTransportMessageHandler implements MessageReceiver
53  {
54      /**
55       * The Service with which this receiver is associated with
56       */
57      protected FlowConstruct flowConstruct;
58  
59      /**
60       * {@link MessageProcessor} chain used to process messages once the transport
61       * specific {@link MessageReceiver} has received transport message and created
62       * the {@link MuleEvent}
63       */
64      protected MessageProcessor listener;
65  
66      /**
67       * Stores the key to this receiver, as used by the Connector to store the
68       * receiver.
69       */
70      protected String receiverKey = null;
71  
72      /**
73       * Stores the endpointUri that this receiver listens on. This enpoint can be
74       * different to the endpointUri in the endpoint stored on the receiver as
75       * endpoint endpointUri may get rewritten if this endpointUri is a wildcard
76       * endpointUri such as jms.*
77       */
78      private EndpointURI endpointUri;
79      
80      protected List<Transformer> defaultInboundTransformers;
81      protected List<Transformer> defaultResponseTransformers;
82  
83      /**
84       * Creates the Message Receiver
85       * 
86       * @param connector the endpoint that created this listener
87       * @param service the service to associate with the receiver. When data is
88       *            received the service <code>dispatchEvent</code> or
89       *            <code>sendEvent</code> is used to dispatch the data to the relevant
90       *            Service.
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         super.initialise();
138     }
139 
140     public FlowConstruct getFlowConstruct()
141     {
142         return flowConstruct;
143     }
144 
145     public final MuleEvent routeMessage(MuleMessage message) throws MuleException
146     {
147         Transaction tx = TransactionCoordination.getInstance().getTransaction();
148         return routeMessage(message, tx, null);
149     }
150 
151     public final MuleEvent routeMessage(MuleMessage message, Transaction trans)
152         throws MuleException
153     {
154         return routeMessage(message, trans, null);
155     }
156 
157     public final MuleEvent routeMessage(MuleMessage message,
158                                           Transaction trans,
159                                           OutputStream outputStream) throws MuleException
160     {
161         return routeMessage(message, new DefaultMuleSession(connector.getMuleContext()), trans,
162             outputStream);
163     }
164 
165     public final MuleEvent routeMessage(MuleMessage message,
166                                           MuleSession session,
167                                           Transaction trans,
168                                           OutputStream outputStream) throws MuleException
169     {
170 
171         final Object o = message.getInboundProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY);
172         if (ObjectUtils.getBoolean(o, false) && !endpoint.getExchangePattern().hasResponse())
173         {
174             logger.warn("MuleClient.send() was used but inbound endpoint "
175                         + endpoint.getEndpointURI().getUri().toString()
176                         + " is not 'request-response'.  No response will be returned.");
177         }
178         
179         message.removeProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY, PropertyScope.INBOUND);
180 
181         MuleEvent muleEvent = createMuleEvent(message, outputStream);
182         muleEvent = OptimizedRequestContext.unsafeSetEvent(muleEvent);
183 
184         if (!endpoint.isDisableTransportTransformer())
185         {
186             applyInboundTransformers(muleEvent);            
187         }
188         MuleEvent resultEvent = listener.process(muleEvent);
189         if (resultEvent != null && resultEvent.getMessage() != null
190             && resultEvent.getMessage().getExceptionPayload() != null 
191             && resultEvent.getMessage().getExceptionPayload().getException() instanceof FilterUnacceptedException)
192         {
193             handleUnacceptedFilter(muleEvent.getMessage());
194             return muleEvent;
195         }
196 
197         if (endpoint.getExchangePattern()== MessageExchangePattern.REQUEST_RESPONSE && resultEvent != null && resultEvent.getMessage() != null && !endpoint.isDisableTransportTransformer())
198         {
199             applyResponseTransformers(resultEvent);
200         }
201         
202         if (connector.isEnableMessageEvents() && endpoint.getExchangePattern().hasResponse())
203         {
204 			connector.fireNotification(new EndpointMessageNotification(
205 					resultEvent.getMessage(), endpoint, resultEvent
206 							.getFlowConstruct().getName(),
207 					EndpointMessageNotification.MESSAGE_RESPONSE));
208         }
209         
210         return resultEvent;
211     }
212     
213     protected void applyInboundTransformers(MuleEvent event) throws MuleException
214     {
215         event.getMessage().applyTransformers(event, defaultInboundTransformers);
216     }
217 
218     protected void applyResponseTransformers(MuleEvent event) throws MuleException
219     {
220         event.getMessage().applyTransformers(event, defaultResponseTransformers);
221     }
222 
223     protected MuleMessage handleUnacceptedFilter(MuleMessage message)
224     {
225         if (logger.isDebugEnabled())
226         {
227             String messageId;
228             messageId = message.getUniqueId();
229             logger.debug("Message " + messageId + " failed to pass filter on endpoint: " + endpoint
230                          + ". Message is being ignored");
231         }
232         return message;
233     }
234 
235     protected MuleEvent createMuleEvent(MuleMessage message, OutputStream outputStream)
236         throws MuleException
237     {
238         ResponseOutputStream ros = null;
239         if (outputStream != null)
240         {
241             if (outputStream instanceof ResponseOutputStream)
242             {
243                 ros = (ResponseOutputStream) outputStream;
244             }
245             else
246             {
247                 ros = new ResponseOutputStream(outputStream);
248             }
249         }
250         MuleSession session;
251         try
252         {
253             session = connector.getSessionHandler().retrieveSessionInfoFromMessage(message);
254         }
255         catch (SerializationException e)
256         {
257             // EE-1820 Support message headers generated by previous Mule versions
258             session = new LegacySessionHandler().retrieveSessionInfoFromMessage(message);
259         }
260         if (session != null)
261         {
262             session.setFlowConstruct(flowConstruct);
263         }
264         else
265         {
266             session = new DefaultMuleSession(flowConstruct, connector.getMuleContext());
267         }
268         return new DefaultMuleEvent(message, endpoint, session, ros);
269     }
270 
271     public EndpointURI getEndpointURI()
272     {
273         return endpointUri;
274     }
275 
276     @Override
277     public String getConnectionDescription()
278     {
279         return endpoint.getEndpointURI().toString();
280     }
281 
282     protected String getConnectEventId()
283     {
284         return connector.getName() + ".receiver (" + endpoint.getEndpointURI() + ")";
285     }
286 
287     // TODO MULE-4871 Receiver key should not be mutable
288     public void setReceiverKey(String receiverKey)
289     {
290         this.receiverKey = receiverKey;
291     }
292 
293     public String getReceiverKey()
294     {
295         return receiverKey;
296     }
297 
298     @Override
299     public InboundEndpoint getEndpoint()
300     {
301         return (InboundEndpoint) super.getEndpoint();
302     }
303 
304     // TODO MULE-4871 Endpoint should not be mutable
305     public void setEndpoint(InboundEndpoint endpoint)
306     {
307         super.setEndpoint(endpoint);
308     }
309 
310     @Override
311     protected WorkManager getWorkManager()
312     {
313         try
314         {
315             return connector.getReceiverWorkManager();
316         }
317         catch (MuleException e)
318         {
319             logger.error(e);
320             return null;
321         }
322     }
323 
324     @Override
325     public String toString()
326     {
327         final StringBuffer sb = new StringBuffer(80);
328         sb.append(ClassUtils.getSimpleName(this.getClass()));
329         sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
330         sb.append(", receiverKey=").append(receiverKey);
331         sb.append(", endpoint=").append(endpoint.getEndpointURI());
332         sb.append('}');
333         return sb.toString();
334     }
335 
336     public void setListener(MessageProcessor processor)
337     {
338         this.listener = processor;
339     }
340 
341     @Override
342     protected void doDispose()
343     {
344         this.listener = null;
345         this.flowConstruct = null;
346         super.doDispose();
347     }
348 }