View Javadoc

1   /*
2    * $Id: DefaultMuleSession.java 11894 2008-06-02 17:32:19Z 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;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleException;
16  import org.mule.api.MuleMessage;
17  import org.mule.api.MuleSession;
18  import org.mule.api.config.MuleProperties;
19  import org.mule.api.endpoint.EndpointNotFoundException;
20  import org.mule.api.endpoint.InboundEndpoint;
21  import org.mule.api.endpoint.OutboundEndpoint;
22  import org.mule.api.routing.OutboundRouterCollection;
23  import org.mule.api.security.SecurityContext;
24  import org.mule.api.service.Service;
25  import org.mule.api.transport.Connector;
26  import org.mule.api.transport.DispatchException;
27  import org.mule.api.transport.ReceiveException;
28  import org.mule.api.transport.SessionHandler;
29  import org.mule.config.i18n.CoreMessages;
30  import org.mule.transport.AbstractConnector;
31  import org.mule.util.UUID;
32  
33  import java.io.IOException;
34  import java.io.ObjectInputStream;
35  import java.io.ObjectOutputStream;
36  import java.util.HashMap;
37  import java.util.Iterator;
38  import java.util.Map;
39  
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  
43  /**
44   * <code>DefaultMuleSession</code> manages the interaction and distribution of events for
45   * Mule UMOs.
46   */
47  
48  public final class DefaultMuleSession implements MuleSession
49  {
50      /**
51       * Serial version
52       */
53      private static final long serialVersionUID = 3380926585676521866L;
54  
55      /**
56       * logger used by this class
57       */
58      private static Log logger = LogFactory.getLog(DefaultMuleSession.class);
59  
60      /**
61       * The Mule service associated with the session
62       */
63      private transient Service service = null;
64  
65      /**
66       * Determines if the service is valid
67       */
68      private boolean valid = true;
69  
70      private String id;
71  
72      private SecurityContext securityContext;
73  
74      private Map properties = null;
75  
76      private transient MuleContext muleContext;
77      
78      public DefaultMuleSession(Service service, MuleContext muleContext)
79      {
80          this.muleContext = muleContext;
81          properties = new HashMap();
82          id = UUID.getUUID();
83          this.service = service;
84      }
85  
86      public DefaultMuleSession(MuleMessage message, SessionHandler requestSessionHandler, Service service, MuleContext muleContext)
87          throws MuleException
88      {
89          this(message, requestSessionHandler, muleContext);
90          if (service == null)
91          {
92              throw new IllegalArgumentException(
93                  CoreMessages.propertiesNotSet("service").toString());
94          }
95          this.service = service;
96      }
97  
98      public DefaultMuleSession(MuleMessage message, SessionHandler requestSessionHandler, MuleContext muleContext) throws MuleException
99      {
100         this.muleContext = muleContext;
101         
102         if (requestSessionHandler == null)
103         {
104             throw new IllegalArgumentException(
105                 CoreMessages.propertiesNotSet("requestSessionHandler").toString());
106         }
107 
108         if (message == null)
109         {
110             throw new IllegalArgumentException(
111                 CoreMessages.propertiesNotSet("message").toString());
112         }
113 
114         properties = new HashMap();
115         requestSessionHandler.retrieveSessionInfoFromMessage(message, this);
116         id = (String) getProperty(requestSessionHandler.getSessionIDKey());
117         if (id == null)
118         {
119             id = UUID.getUUID();
120             if (logger.isDebugEnabled())
121             {
122                 logger.debug("There is no session id on the request using key: "
123                              + requestSessionHandler.getSessionIDKey() + ". Generating new session id: " + id);
124             }
125         }
126         else if (logger.isDebugEnabled())
127         {
128             logger.debug("Got session with id: " + id);
129         }
130     }
131 
132     public void dispatchEvent(MuleMessage message) throws MuleException
133     {
134         if (service == null)
135         {
136             throw new IllegalStateException(CoreMessages.objectIsNull("Service").getMessage());
137         }
138 
139         OutboundRouterCollection router = service.getOutboundRouter();
140         if (router == null)
141         {
142             throw new EndpointNotFoundException(
143                 CoreMessages.noOutboundRouterSetOn(service.getName()));
144         }
145         router.route(message, this, false);
146     }
147 
148     public void dispatchEvent(MuleMessage message, String endpointName) throws MuleException
149     {
150         dispatchEvent(message,  muleContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(endpointName));
151     }
152  
153     public void dispatchEvent(MuleMessage message, OutboundEndpoint endpoint) throws MuleException
154     {
155         if (endpoint == null)
156         {
157             logger.warn("Endpoint argument is null, using outbound router to determine endpoint.");
158             dispatchEvent(message);
159         }
160 
161         if (logger.isDebugEnabled())
162         {
163             logger.debug("MuleSession has received asynchronous event on: " + endpoint);
164         }
165 
166         MuleEvent event = createOutboundEvent(message, endpoint, null);
167 
168         dispatchEvent(event);
169 
170         processResponse(event.getMessage());
171     }
172 
173     public MuleMessage sendEvent(MuleMessage message, String endpointName) throws MuleException
174     {
175         return sendEvent(message, muleContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(endpointName));
176     }
177 
178     public MuleMessage sendEvent(MuleMessage message) throws MuleException
179     {
180         if (service == null)
181         {
182             throw new IllegalStateException(CoreMessages.objectIsNull("Service").getMessage());
183         }
184         OutboundRouterCollection router = service.getOutboundRouter();
185         if (router == null)
186         {
187             throw new EndpointNotFoundException(
188                 CoreMessages.noOutboundRouterSetOn(service.getName()));
189         }
190         MuleMessage result = router.route(message, this, true);
191         if (result != null)
192         {
193             processResponse(result);
194         }
195 
196         return result;
197     }
198 
199     public MuleMessage sendEvent(MuleMessage message, OutboundEndpoint endpoint) throws MuleException
200     {
201         if (endpoint == null)
202         {
203             logger.warn("Endpoint argument is null, using outbound router to determine endpoint.");
204             return sendEvent(message);
205         }
206 
207         if (logger.isDebugEnabled())
208         {
209             logger.debug("MuleSession has received synchronous event on endpoint: " + endpoint);
210         }
211 
212         MuleEvent event = createOutboundEvent(message, endpoint, null);
213         MuleMessage result = sendEvent(event);
214 
215         // Handles the situation where a response has been received via a remote
216         // ReplyTo channel.
217         if (endpoint.isRemoteSync() && result != null)
218         {
219             result.applyTransformers(endpoint.getResponseTransformers());
220         }
221 
222         if (result != null)
223         {
224             processResponse(result);
225         }
226 
227         return result;
228     }
229 
230     /*
231      * (non-Javadoc)
232      *
233      * @see org.mule.api.MuleSession#dispatchEvent(org.mule.api.MuleEvent)
234      */
235     public void dispatchEvent(MuleEvent event) throws MuleException
236     {
237         if (event.getEndpoint() instanceof OutboundEndpoint)
238         {
239             try
240             {
241                 if (logger.isDebugEnabled())
242                 {
243                     logger.debug("dispatching event: " + event);
244                 }
245 
246                 Connector connector = event.getEndpoint().getConnector();
247 
248                 if (connector instanceof AbstractConnector)
249                 {
250                     ((AbstractConnector) connector).getSessionHandler().storeSessionInfoToMessage(this,
251                         event.getMessage());
252                 }
253                 else
254                 {
255                     // TODO in Mule 2.0 we'll flatten the Connector hierachy
256                     logger.warn("A session handler could not be obtained, using  default");
257                     new MuleSessionHandler().storeSessionInfoToMessage(this, event.getMessage());
258                 }
259 
260                 ((OutboundEndpoint) event.getEndpoint()).dispatch(event);
261             }
262             catch (Exception e)
263             {
264                 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
265             }
266         }
267         else if (service != null)
268         {
269             if (logger.isDebugEnabled())
270             {
271                 logger.debug("dispatching event to service: " + service.getName()
272                              + ", event is: " + event);
273             }
274             service.dispatchEvent(event);
275             processResponse(event.getMessage());
276         }
277         else
278         {
279             throw new DispatchException(CoreMessages.noComponentForEndpoint(), event.getMessage(),
280                 event.getEndpoint());
281         }
282     }
283 
284     public String getId()
285     {
286         return id;
287     }
288 
289     /*
290      * (non-Javadoc)
291      *
292      * @see org.mule.api.MuleSession#sendEvent(org.mule.api.MuleEvent)
293      */
294     // TODO This method is practically the same as dispatchEvent(MuleEvent event),
295     // so we could use some refactoring here.
296     public MuleMessage sendEvent(MuleEvent event) throws MuleException
297     {
298         int timeout = event.getMessage().getIntProperty(MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, -1);
299         if (timeout >= 0)
300         {
301             event.setTimeout(timeout);
302         }
303 
304         if (event.getEndpoint() instanceof OutboundEndpoint)
305         {
306             try
307             {
308                 if (logger.isDebugEnabled())
309                 {
310                     logger.debug("sending event: " + event);
311                 }
312 
313                 Connector connector = event.getEndpoint().getConnector();
314 
315                 if (connector instanceof AbstractConnector)
316                 {
317                     ((AbstractConnector) connector).getSessionHandler().storeSessionInfoToMessage(this,
318                         event.getMessage());
319                 }
320                 else
321                 {
322                     // TODO in Mule 2.0 we'll flatten the Connector hierachy
323                     logger.warn("A session handler could not be obtained, using default.");
324                     new MuleSessionHandler().storeSessionInfoToMessage(this, event.getMessage());
325                 }
326 
327                 MuleMessage response = ((OutboundEndpoint) event.getEndpoint()).send(event);
328                 // See MULE-2692
329                 //RM* This actually performs the function of adding properties from the request to the response
330                 // message I think this could be done without the performance hit.
331                 //Or we could provide a way to set the request message as the OriginalAdapter on the message
332                 //And provide access to the request properties that way
333                 response = OptimizedRequestContext.unsafeRewriteEvent(response);
334                 processResponse(response);
335                 return response;
336             }
337             catch (MuleException e)
338             {
339                 throw e;
340             }
341             catch (Exception e)
342             {
343                 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
344             }
345 
346         }
347         else if (service != null)
348         {
349             if (logger.isDebugEnabled())
350             {
351                 logger.debug("sending event to service: " + service.getName()
352                              + " event is: " + event);
353             }
354             return service.sendEvent(event);
355 
356         }
357         else
358         {
359             throw new DispatchException(CoreMessages.noComponentForEndpoint(), event.getMessage(),
360                 event.getEndpoint());
361         }
362     }
363 
364     /**
365      * Once an event has been processed we need to romove certain properties so that
366      * they not propagated to the next request
367      *
368      * @param response The response from the previous request
369      */
370     protected void processResponse(MuleMessage response)
371     {
372         if (response == null)
373         {
374             return;
375         }
376     }
377 
378     /*
379      * (non-Javadoc)
380      *
381      * @see org.mule.api.MuleSession#isValid()
382      */
383     public boolean isValid()
384     {
385         return valid;
386     }
387 
388     /*
389      * (non-Javadoc)
390      *
391      * @see org.mule.api.MuleSession#setValid(boolean)
392      */
393     public void setValid(boolean value)
394     {
395         valid = value;
396     }
397 
398     /*
399      * (non-Javadoc)
400      *
401      * @see org.mule.api.MuleSession#receiveEvent(org.mule.api.endpoint.Endpoint,
402      *      long, org.mule.api.MuleEvent)
403      */
404     public MuleMessage requestEvent(String endpointName, long timeout) throws MuleException
405     {
406         InboundEndpoint endpoint = RegistryContext.getRegistry().lookupEndpointFactory().getInboundEndpoint(endpointName);
407         return requestEvent(endpoint, timeout);
408     }
409 
410     /*
411      * (non-Javadoc)
412      *
413      * @see org.mule.api.MuleSession#receiveEvent(org.mule.api.endpoint.Endpoint,
414      *      long, org.mule.api.MuleEvent)
415      */
416     public MuleMessage requestEvent(InboundEndpoint endpoint, long timeout) throws MuleException
417     {
418         try
419         {
420             return endpoint.request(timeout);
421         }
422         catch (Exception e)
423         {
424             throw new ReceiveException(endpoint, timeout, e);
425         }
426     }
427 
428     public MuleEvent createOutboundEvent(MuleMessage message,
429                                         OutboundEndpoint endpoint,
430                                         MuleEvent previousEvent) throws MuleException
431     {
432         if (endpoint == null)
433         {
434             throw new DispatchException(CoreMessages.objectIsNull("Outbound Endpoint"), message,
435                 endpoint);
436         }
437 
438         if (logger.isDebugEnabled())
439         {
440             logger.debug("Creating event with data: " + message.getPayload().getClass().getName()
441                          + ", for endpoint: " + endpoint);
442         }
443 
444         try
445         {
446             MuleEvent event;
447             if (previousEvent != null)
448             {
449                 event = new DefaultMuleEvent(message, endpoint, service, previousEvent);
450             }
451             else
452             {
453                 event = new DefaultMuleEvent(message, endpoint, this, false, null);
454             }
455             return event;
456         }
457         catch (Exception e)
458         {
459             throw new DispatchException(
460                 CoreMessages.failedToCreate("MuleEvent"), message, endpoint, e);
461         }
462     }
463 
464     /**
465      * @return Returns the service.
466      */
467     public Service getService()
468     {
469         return service;
470     }
471 
472     void setService(Service service)
473     {
474         this.service = service;
475     }
476 
477     /**
478      * The security context for this session. If not null outbound, inbound and/or
479      * method invocations will be authenticated using this context
480      * 
481      * @param context the context for this session or null if the request is not
482      *            secure.
483      */
484     public void setSecurityContext(SecurityContext context)
485     {
486         securityContext = context;
487     }
488 
489     /**
490      * The security context for this session. If not null outbound, inbound and/or
491      * method invocations will be authenticated using this context
492      * 
493      * @return the context for this session or null if the request is not secure.
494      */
495     public SecurityContext getSecurityContext()
496     {
497         return securityContext;
498     }
499 
500     /**
501      * Will set a session level property. These will either be stored and retrieved
502      * using the underlying transport mechanism of stored using a default mechanism
503      * 
504      * @param key the key for the object data being stored on the session
505      * @param value the value of the session data
506      */
507     public void setProperty(Object key, Object value)
508     {
509         properties.put(key, value);
510     }
511 
512     /**
513      * Will retrieve a session level property.
514      * 
515      * @param key the key for the object data being stored on the session
516      * @return the value of the session data or null if the property does not exist
517      */
518     public Object getProperty(Object key)
519     {
520         return properties.get(key);
521     }
522 
523     /**
524      * Will retrieve a session level property and remove it from the session
525      * 
526      * @param key the key for the object data being stored on the session
527      * @return the value of the session data or null if the property does not exist
528      */
529     public Object removeProperty(Object key)
530     {
531         return properties.remove(key);
532     }
533 
534     /**
535      * Returns an iterater of property keys for the session properties on this
536      * session
537      * 
538      * @return an iterater of property keys for the session properties on this
539      *         session
540      */
541     public Iterator getPropertyNames()
542     {
543         return properties.keySet().iterator();
544     }
545     
546     private void writeObject(ObjectOutputStream out) throws IOException
547     {
548         out.defaultWriteObject();
549         out.writeObject(getService().getName());
550     }
551 
552     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
553     {
554         in.defaultReadObject();
555         String serviceName = (String) in.readObject();
556         service = RegistryContext.getRegistry().lookupService(serviceName);
557         muleContext = MuleServer.getMuleContext();
558     }
559 
560 }