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