View Javadoc

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