View Javadoc

1   /*
2    * $Id: DefaultMuleSession.java 22686 2011-08-16 19:39:20Z pablo.lagreca $
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.session;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.MuleException;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.MuleSession;
17  import org.mule.api.construct.FlowConstruct;
18  import org.mule.api.security.SecurityContext;
19  import org.mule.api.transport.SessionHandler;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.util.CaseInsensitiveHashMap;
22  import org.mule.util.UUID;
23  import org.mule.util.store.DeserializationPostInitialisable;
24  
25  import java.io.IOException;
26  import java.io.ObjectInputStream;
27  import java.io.ObjectOutputStream;
28  import java.io.OptionalDataException;
29  import java.io.Serializable;
30  import java.util.Collections;
31  import java.util.HashMap;
32  import java.util.Iterator;
33  import java.util.Map;
34  import java.util.Set;
35  
36  import org.apache.commons.collections.map.CaseInsensitiveMap;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  /**
41   * <code>DefaultMuleSession</code> manages the interaction and distribution of events for
42   * Mule Services.
43   */
44  
45  public final class DefaultMuleSession implements MuleSession, DeserializationPostInitialisable
46  {
47      /**
48       * Serial version
49       */
50      private static final long serialVersionUID = 3380926585676521866L;
51  
52      /**
53       * logger used by this class
54       */
55      private static Log logger = LogFactory.getLog(DefaultMuleSession.class);
56  
57      /**
58       * The Mule service associated with the session
59       * <p/>
60       * Note: This object uses custom serialization via the writeObject()/readObject() methods.
61       */
62      private transient FlowConstruct flowConstruct = null;
63  
64      /**
65       * Determines if the service is valid
66       */
67      private boolean valid = true;
68  
69      private String id;
70  
71      /**
72       * The security context associated with the session.
73       * Note that this context will only be serialized if the SecurityContext object is Serializable.
74       */
75      private SecurityContext securityContext;
76  
77      private Map<String, Object> properties = null;
78  
79      /**
80       * The Mule context
81       * <p/>
82       * Note: This object uses custom serialization via the readObject() method.
83       */
84      private transient MuleContext muleContext;
85  
86      private transient Map<String, Object> serializedData = null;
87  
88      public DefaultMuleSession(MuleContext muleContext)
89      {
90          this((FlowConstruct) null, muleContext);
91      }
92  
93      public DefaultMuleSession(FlowConstruct flowConstruct, MuleContext muleContext)
94      {
95          this.muleContext = muleContext;
96          properties = Collections.synchronizedMap(new CaseInsensitiveHashMap/*<String, Object>*/());
97          id = UUID.getUUID();
98          this.flowConstruct = flowConstruct;
99      }
100 
101     /**
102      * @deprecated Use DefaultMuleSession(Service service, MuleContext muleContext) instead
103      */
104     @Deprecated
105     public DefaultMuleSession(MuleMessage message,
106                               SessionHandler requestSessionHandler,
107                               FlowConstruct flowConstruct,
108                               MuleContext muleContext) throws MuleException
109     {
110         this(message, requestSessionHandler, muleContext);
111         if (flowConstruct == null)
112         {
113             throw new IllegalArgumentException(CoreMessages.propertiesNotSet("flowConstruct").toString());
114         }
115         this.flowConstruct = flowConstruct;
116     }
117 
118     /**
119      * @deprecated Use DefaultMuleSession(MuleContext muleContext) instead
120      */
121     @Deprecated
122     public DefaultMuleSession(MuleMessage message, SessionHandler requestSessionHandler, MuleContext muleContext) throws MuleException
123     {
124         this(muleContext);
125 
126         if (requestSessionHandler == null)
127         {
128             throw new IllegalArgumentException(
129                     CoreMessages.propertiesNotSet("requestSessionHandler").toString());
130         }
131 
132         if (message == null)
133         {
134             throw new IllegalArgumentException(
135                     CoreMessages.propertiesNotSet("message").toString());
136         }
137 
138         properties = new CaseInsensitiveMap/*<String, Object>*/();
139         requestSessionHandler.retrieveSessionInfoFromMessage(message, this);
140         id = getProperty(requestSessionHandler.getSessionIDKey());
141         if (id == null)
142         {
143             id = UUID.getUUID();
144             if (logger.isDebugEnabled())
145             {
146                 logger.debug("There is no session id on the request using key: "
147                         + requestSessionHandler.getSessionIDKey() + ". Generating new session id: " + id);
148             }
149         }
150         else if (logger.isDebugEnabled())
151         {
152             logger.debug("Got session with id: " + id);
153         }
154     }
155 
156     public DefaultMuleSession(MuleSession session, MuleContext muleContext)
157     {
158         this.muleContext = muleContext;
159         this.id = session.getId();
160         this.securityContext = session.getSecurityContext();
161         this.flowConstruct = session.getFlowConstruct();
162         this.valid = session.isValid();
163 
164         this.properties = new HashMap<String, Object>();
165         for (String key : session.getPropertyNamesAsSet())
166         {
167             this.properties.put(key, session.getProperty(key));
168         }
169     }
170 
171     /**
172      * Copy the session, changing only the flow construct.  This can be used for
173      * synchronous calls from one flow construct to another.
174      */
175     public DefaultMuleSession(MuleSession source, FlowConstruct flowConstruct)
176     {
177         this.flowConstruct = flowConstruct;
178         DefaultMuleSession session = (DefaultMuleSession) source;
179         this.id = session.id;
180         this.muleContext = session.muleContext;
181         this.properties = session.properties;
182         this.securityContext = session.securityContext;
183         this.valid = session.valid;
184     }
185 
186     @Override
187     public String getId()
188     {
189         return id;
190     }
191 
192     @Override
193     public boolean isValid()
194     {
195         return valid;
196     }
197 
198     @Override
199     public void setValid(boolean value)
200     {
201         valid = value;
202     }
203 
204     /**
205      * @return Returns the service.
206      */
207     @Override
208     public FlowConstruct getFlowConstruct()
209     {
210         return flowConstruct;
211     }
212 
213     @Override
214     public void setFlowConstruct(FlowConstruct flowConstruct)
215     {
216         this.flowConstruct = flowConstruct;
217     }
218 
219     /**
220      * The security context for this session. If not null outbound, inbound and/or
221      * method invocations will be authenticated using this context
222      *
223      * @param context the context for this session or null if the request is not
224      *                secure.
225      */
226     @Override
227     public void setSecurityContext(SecurityContext context)
228     {
229         securityContext = context;
230     }
231 
232     /**
233      * The security context for this session. If not null outbound, inbound and/or
234      * method invocations will be authenticated using this context
235      *
236      * @return the context for this session or null if the request is not secure.
237      */
238     @Override
239     public SecurityContext getSecurityContext()
240     {
241         return securityContext;
242     }
243 
244     /**
245      * Will set a session level property. These will either be stored and retrieved
246      * using the underlying transport mechanism of stored using a default mechanism
247      *
248      * @param key   the key for the object data being stored on the session
249      * @param value the value of the session data
250      */
251     @Override
252     public void setProperty(String key, Object value)
253     {
254         properties.put(key, value);
255     }
256 
257     /**
258      * Will retrieve a session level property.
259      *
260      * @param key the key for the object data being stored on the session
261      * @return the value of the session data or null if the property does not exist
262      */
263     @Override
264     @SuppressWarnings("unchecked")
265     public <T> T getProperty(Object key)
266     {
267         return (T) properties.get(key);
268     }
269 
270     /**
271      * Will retrieve a session level property and remove it from the session
272      *
273      * @param key the key for the object data being stored on the session
274      * @return the value of the session data or null if the property does not exist
275      */
276     @Override
277     public Object removeProperty(Object key)
278     {
279         return properties.remove(key);
280     }
281 
282     /**
283      * Returns an iterater of property keys for the session properties on this
284      * session
285      *
286      * @return an iterater of property keys for the session properties on this
287      *         session
288      * @deprecated Use getPropertyNamesAsSet() instead
289      */
290     @Override
291     @Deprecated
292     public Iterator<String> getPropertyNames()
293     {
294         return properties.keySet().iterator();
295     }
296 
297     @Override
298     public Set<String> getPropertyNamesAsSet()
299     {
300         return Collections.unmodifiableSet(properties.keySet());
301     }
302 
303     public void merge(MuleSession updatedSession)
304     {
305         if (updatedSession == null)
306         {
307             return;
308         }
309         Map<String, Object> oldProperties = this.properties;
310         this.properties = Collections.synchronizedMap(new CaseInsensitiveHashMap/*<String, Object>*/());
311         for (String propertyKey : updatedSession.getPropertyNamesAsSet())
312         {
313             this.properties.put(propertyKey, updatedSession.<Object>getProperty(propertyKey));
314         }
315         for (String propertyKey : oldProperties.keySet())
316         {
317             if (!this.properties.containsKey(propertyKey) && !(oldProperties.get(propertyKey) instanceof Serializable))
318             {
319                 this.properties.put(propertyKey, oldProperties.get(propertyKey));
320             }
321         }
322     }
323 
324     ////////////////////////////
325     // Serialization methods
326     ////////////////////////////
327 
328     private void writeObject(ObjectOutputStream out) throws IOException
329     {
330         out.defaultWriteObject();
331         //Can be null if service call originates from MuleClient
332         if (serializedData != null)
333         {
334             Object serviceName = serializedData.get("serviceName");
335             if (serviceName != null)
336             {
337                 out.writeObject(serviceName);
338             }
339         }
340         else
341         {
342             if (getFlowConstruct() != null)
343             {
344                 out.writeObject(getFlowConstruct() != null ? getFlowConstruct().getName() : "null");
345             }
346         }
347     }
348 
349     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
350     {
351         in.defaultReadObject();
352         serializedData = new HashMap<String, Object>();
353 
354         try
355         {
356             //Optional
357             serializedData.put("serviceName", in.readObject());
358         }
359         catch (OptionalDataException e)
360         {
361             //ignore
362         }
363     }
364 
365     /**
366      * Invoked after deserialization. This is called when the marker interface
367      * {@link org.mule.util.store.DeserializationPostInitialisable} is used. This will get invoked
368      * after the object has been deserialized passing in the current mulecontext when using either
369      * {@link org.mule.transformer.wire.SerializationWireFormat},
370      * {@link org.mule.transformer.wire.SerializedMuleMessageWireFormat}, or the
371      * {@link org.mule.transformer.simple.ByteArrayToSerializable} transformer.
372      *
373      * @param context the current muleContext instance
374      * @throws MuleException if there is an error initializing
375      */
376     public void initAfterDeserialisation(MuleContext context) throws MuleException
377     {
378         // this method can be called even on objects that were not serialized. In this case,
379         // the temporary holder for serialized data is not initialized and we can just return
380         if (serializedData == null)
381         {
382             return;
383         }
384 
385         String serviceName = (String) serializedData.get("serviceName");
386         //Can be null if service call originates from MuleClient
387         if (serviceName != null)
388         {
389             flowConstruct = context.getRegistry().lookupFlowConstruct(serviceName);
390         }
391         serializedData = null;
392     }
393 }