View Javadoc

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