View Javadoc

1   /*
2    * $Id: RequestContext.java 7963 2007-08-21 08:53:15Z 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.config.MuleProperties;
14  import org.mule.umo.UMOEvent;
15  import org.mule.umo.UMOEventContext;
16  import org.mule.umo.UMOExceptionPayload;
17  import org.mule.umo.UMOMessage;
18  
19  import java.util.Iterator;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  
24  /**
25   * <code>RequestContext</code> is a thread context where components can get the
26   * current event or set response properties that will be sent on the outgoing
27   * message.
28   *
29   * <p>RequestContext seems to be used to allow thread local mutation of events that
30   * are not otherwise available in the scope.  so this is a good place to create a new
31   * thread local copy - it will be read because supporting code is expecting mutation.</p>
32   *
33   */
34  public final class RequestContext
35  {
36      // setting this to false gives old semantics in non-critical cases
37      private static boolean SAFE = true;
38      private static final Log logger = LogFactory.getLog(RequestContext.class);
39      private static final ThreadLocal currentEvent = new ThreadLocal();
40  
41      /** Do not instanciate. */
42      protected RequestContext()
43      {
44          // no-op
45      }
46  
47      public static UMOEventContext getEventContext()
48      {
49          UMOEvent event = getEvent();
50          if (event != null)
51          {
52              return new MuleEventContext(event);
53          }
54          else
55          {
56              return null;
57          }
58      }
59  
60      public static UMOEvent getEvent()
61      {
62          return (UMOEvent) currentEvent.get();
63      }
64  
65      /**
66       * Set an event for out-of-scope thread access.  Safe: use by default
67       *
68       * @param event - the event to set
69       * @return A new mutable copy of the event set
70       */
71      public static UMOEvent setEvent(UMOEvent event)
72      {
73          return internalSetEvent(newEvent(event, SAFE, false));
74      }
75  
76      protected static UMOEvent internalSetEvent(UMOEvent event)
77      {
78          currentEvent.set(event);
79          return event;
80      }
81  
82      /**
83       * Sets a new message payload in the RequestContext but maintains all other
84       * properties (session, endpoint, synchronous, etc.) from the previous event.
85       * Safe: use by default
86       *
87       * @param message - the new message payload
88       * @return A new copy of the message set
89       */
90      public static UMOMessage rewriteEvent(UMOMessage message)
91      {
92          return internalRewriteEvent(message, SAFE, false);
93      }
94  
95      protected static UMOMessage internalRewriteEvent(UMOMessage message, boolean safe, boolean required)
96      {
97          if (message != null)
98          {
99              UMOEvent event = getEvent();
100             if (event != null)
101             {
102                 UMOMessage copy = newMessage(message, safe, required);
103                 UMOEvent newEvent = new MuleEvent(copy, event);
104                 if (safe)
105                 {
106                     resetAccessControl(copy);
107                 }
108                 internalSetEvent(newEvent);
109                 return copy;
110             }
111         }
112         return message;
113     }
114 
115     public static UMOMessage writeResponse(UMOMessage message)
116     {
117         return internalWriteResponse(message, SAFE, false);
118     }
119 
120     protected static UMOMessage internalWriteResponse(UMOMessage message, boolean safe, boolean required)
121     {
122         if (message != null)
123         {
124             UMOEvent event = getEvent();
125             if (event != null)
126             {
127                 UMOMessage copy = newMessage(message, safe, required);
128                 combineProperties(event, copy);
129                 MuleEvent newEvent = new MuleEvent(copy, event.getEndpoint(), event.getSession(), event.isSynchronous());
130                 if (safe)
131                 {
132                     resetAccessControl(copy);
133                 }
134                 internalSetEvent(newEvent);
135                 return copy;
136             }
137         }
138         return message;
139     }
140 
141     protected static void combineProperties(UMOEvent event, UMOMessage message)
142     {
143         for (Iterator iterator = event.getMessage().getPropertyNames().iterator(); iterator.hasNext();)
144         {
145             String key = (String) iterator.next();
146             if (key == null)
147             {
148                 logger.warn("Message property key is null: please report the following stack trace to dev@mule.codehaus.org.",
149                         new IllegalArgumentException());
150             }
151             else
152             {
153                 if (key.startsWith(MuleProperties.PROPERTY_PREFIX))
154                 {
155                     Object newValue = message.getProperty(key);
156                     Object oldValue = event.getMessage().getProperty(key);
157                     if (newValue == null)
158                     {
159                         message.setProperty(key, oldValue);
160                     }
161                     else if (logger.isInfoEnabled() && !newValue.equals(oldValue))
162                     {
163                         logger.info("Message already contains property " + key + "=" + newValue
164                                 + " not replacing old value: " + oldValue);
165                     }
166                 }
167             }
168         }
169     }
170 
171     /**
172      * Resets the current request context (clears all information).
173      */
174     public static void clear()
175     {
176         setEvent(null);
177     }
178 
179     public static void setExceptionPayload(UMOExceptionPayload exceptionPayload)
180     {
181         getEvent().getMessage().setExceptionPayload(exceptionPayload);
182     }
183 
184     public static UMOExceptionPayload getExceptionPayload()
185     {
186         return getEvent().getMessage().getExceptionPayload();
187     }
188 
189 
190     // utility methods for thread safe access
191 
192     protected static void noteUse(String type)
193     {
194         if (logger.isDebugEnabled())
195         {
196             logger.debug("copying " + type, new Exception());
197         }
198     }
199 
200     protected static UMOEvent newEvent(UMOEvent event, boolean safe, boolean required)
201     {
202         if (safe && event instanceof ThreadSafeAccess)
203         {
204             if (! required)
205             {
206                 noteUse("event");
207             }
208             return (UMOEvent) ((ThreadSafeAccess)event).newThreadCopy();
209         }
210         else
211         {
212             return event;
213         }
214     }
215 
216     protected static UMOMessage newMessage(UMOMessage message, boolean safe, boolean required)
217     {
218         if (safe && message instanceof ThreadSafeAccess)
219         {
220             if (! required)
221             {
222                 noteUse("message");
223             }
224             return (UMOMessage) ((ThreadSafeAccess)message).newThreadCopy();
225         }
226         else
227         {
228             return message;
229         }
230     }
231 
232     protected static void resetAccessControl(Object object)
233     {
234         if (object instanceof ThreadSafeAccess)
235         {
236             ((ThreadSafeAccess) object).resetAccessControl();
237         }
238     }
239 
240 }