You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2008/10/23 11:26:33 UTC

svn commit: r707325 - in /myfaces/trinidad/branches/1.2.9.1-branch: trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/co...

Author: matzew
Date: Thu Oct 23 02:26:32 2008
New Revision: 707325

URL: http://svn.apache.org/viewvc?rev=707325&view=rev
Log:
TRINIDAD-1273 - Apply a request lifecuycle to ThreadLocals so that their contents don't leak across requests

Thanks to Blake Sullivan for his patch

Added:
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ThreadLocalUtils.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ThreadLocalResetter.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalLifecycle.REQUEST
Modified:
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanFactory.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RenderingContext.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/FastMessageFormat.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/MessageFactory.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuUtils.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/table/TableRenderingContext.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/webapp/TrinidadFilterImpl.java

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanFactory.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanFactory.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanFactory.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/FacesBeanFactory.java Thu Oct 23 02:26:32 2008
@@ -32,6 +32,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
 
 
 /**
@@ -272,7 +273,7 @@
   static private Map<Object, Object> _TYPES_MAP;
   static private Map<String, Class<?>> _TYPES_CLASS = new ConcurrentHashMap<String, Class<?>>();
   static private final ThreadLocal<StringBuilder> _STRING_BUILDER =
-                                                        new ThreadLocal<StringBuilder>();
+                                                         ThreadLocalUtils.newRequestThreadLocal();
 
   static
   {

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java Thu Oct 23 02:26:32 2008
@@ -59,6 +59,7 @@
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
 import org.apache.myfaces.trinidad.render.ExtendedRenderer;
 import org.apache.myfaces.trinidad.render.LifecycleRenderer;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
 
 
 /**
@@ -1478,7 +1479,7 @@
 
 
   static private final ThreadLocal<StringBuilder> _STRING_BUILDER =
-                                                        new ThreadLocal<StringBuilder>();
+                                                          ThreadLocalUtils.newRequestThreadLocal();
 
   static private FacesBean.Type _createType()
   {

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RenderingContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RenderingContext.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RenderingContext.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/context/RenderingContext.java Thu Oct 23 02:26:32 2008
@@ -25,6 +25,7 @@
 
 import org.apache.myfaces.trinidad.skin.Skin;
 import org.apache.myfaces.trinidad.skin.Icon;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
 
 /**
  */
@@ -150,7 +151,7 @@
 
 
   static private final ThreadLocal<RenderingContext> _CURRENT_CONTEXT = 
-    new ThreadLocal<RenderingContext>();
+                                                           ThreadLocalUtils.newRequestThreadLocal();  
   
   static private final TrinidadLogger _LOG =
     TrinidadLogger.createTrinidadLogger(RenderingContext.class);

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/FastMessageFormat.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/FastMessageFormat.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/FastMessageFormat.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/FastMessageFormat.java Thu Oct 23 02:26:32 2008
@@ -6,9 +6,9 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -24,7 +24,7 @@
  * The FastMessageFormat class is a greatly reduced version
  * of the java.text.MessageFormat class.  It's also much faster
  * and much less expensive to create, which is especially
- * valuable when it is created and thrown away many times - 
+ * valuable when it is created and thrown away many times -
  * a common use case in web applications.
  * <p>
  * The only syntax supported by this class is simple index-based
@@ -130,33 +130,29 @@
             }
             else
             {
-              if ((patternChar < '0') ||
-                  (patternChar > '9'))
-                throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString(
-                  "FASTMESSAGEFORMAT_ONLY_SUPPORT_NUMERIC_ARGUMENTS"));
+              if ((patternChar < '0') || (patternChar > '9'))
+                throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString("FASTMESSAGEFORMAT_ONLY_SUPPORT_NUMERIC_ARGUMENTS"));
               sourceIndex = (sourceIndex * 10) + (patternChar - '0');
             }
           }
 
           if (j == formatLength)
-            throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString(
-              "END_OF_PATTERN_NOT_FOUND"));
+            throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString("END_OF_PATTERN_NOT_FOUND"));
           if (j == i + 1)
-            throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString(
-              "FASTMESSAGEFORMAT_FIND_EMPTY_ARGUMENT"));
+            throw new IllegalArgumentException(_LOG.getLogger().getResourceBundle().getString("FASTMESSAGEFORMAT_FIND_EMPTY_ARGUMENT"));
           if (sourceIndex < sourceCount)
           {
             Object sourceString = source[sourceIndex];
             if (sourceString != null)
               buffer.append(sourceString.toString());
           }
-          
+
           i = j;
           lastStart = i + 1;
         }
         else
         {
-           // Do nothing.  The character will be added in later
+          // Do nothing.  The character will be added in later
           ;
         }
       }
@@ -167,11 +163,85 @@
     return new String(buffer);
   }
 
-  private final char[] _formatText;
-  private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
-    FastMessageFormat.class);
-}
+  /**
+   * Formats the given array of strings based on the initial
+   * pattern.   It is legal for this array to be shorter
+   * than that indicated by the pattern, or to have null
+   * entries - these will simply be ignored.
+   * This formatter will only replace expressions of the type "{[0-9]+}".
+   * Any other use of '{}' will be interpreted as literal text.
+   * This is the same behavior as TrFastMessageFormatUtils.format on the client.
+   * <p>
+   * @param source an array of strings
+   */
+  public String formatLikeClient(Object[] source)
+  {
+    int formatLength = _formatText.length;
+    int length = 0;
+    int sourceCount = source.length;
+    for (int i = 0; i < sourceCount; i++)
+    {
+      Object sourceString = source[i];
+      if (sourceString != null)
+      {
+        length += sourceString.toString().length();
+      }
+    }
+
+    StringBuffer buffer = new StringBuffer(length + formatLength);
+
+    int lastStart = 0;
+    for (int i = 0; i < formatLength; i++)
+    {
+      char ch = _formatText[i];
+      if (ch == '{')
+      {
+        buffer.append(_formatText, lastStart, i - lastStart);
+
+        int sourceIndex = 0;
+        int j = i + 1;
+        char patternChar = ' ';
+        for (; j < formatLength; j++)
+        {
+          patternChar = _formatText[j];
+          if ((patternChar < '0') || (patternChar > '9'))
+            break;
+          sourceIndex = (sourceIndex * 10) + (patternChar - '0');
+        }
+
+        if (j > i + 1 && patternChar == '}')
+        {
+          if (sourceIndex < sourceCount)
+          {
+            Object sourceString = source[sourceIndex];
+            if (sourceString != null)
+              buffer.append(sourceString.toString());
+          }
+          i = j;
+        }
+        else
+        {
+          // interpret the chars literally
+          buffer.append(_formatText, i, j - i);
+          i = j - 1;
+        }      
+        
+        lastStart = i + 1;
+      }
+      else
+      {
+        // Do nothing.  The character will be added in later
+        ;
+      }
+    }
 
+    buffer.append(_formatText, lastStart, formatLength - lastStart);
 
+    return new String(buffer);
+  }
 
+  private final char[] _formatText;
+  private static final TrinidadLogger _LOG =
+    TrinidadLogger.createTrinidadLogger(FastMessageFormat.class);
+}
 

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/MessageFactory.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/MessageFactory.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/MessageFactory.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/MessageFactory.java Thu Oct 23 02:26:32 2008
@@ -430,7 +430,7 @@
   {
     if (parameters == null)
       return pattern;
-
+    
     FastMessageFormat formatter = new FastMessageFormat(pattern);
     String fmtedMsgStr = formatter.format(parameters);
     return fmtedMsgStr;
@@ -610,7 +610,7 @@
       _customDetailErrorMessage = customDetailErrorMessage;
       _hasBoundParameters = hasBoundParameters;
     }
-
+    
     // Currently only detail message can be customized. So we override the
     // detail message. If summary is to be overridden we have to do the
     // same to it also.
@@ -619,6 +619,7 @@
     {
       FacesContext context    = FacesContext.getCurrentInstance();
       String detailMsgPattern = (String)_customDetailErrorMessage.getValue(context.getELContext());
+      
       if(detailMsgPattern == null)
       {
         // Set a default message that might get used by FacesException 
@@ -631,7 +632,10 @@
         
         // Since that string will get parsed by FastMessageFormat, the { } 
         // of the EL must be escaped
-        detailMsgPattern = '\'' + detailMsgPattern + '\'';
+        //detailMsgPattern = '\'' + detailMsgPattern + '\'';
+        
+        // No need to format this string, just return it here.
+        return detailMsgPattern;
       }
       
       Object[] params = super.getParameters();

Added: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ThreadLocalUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ThreadLocalUtils.java?rev=707325&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ThreadLocalUtils.java (added)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/ThreadLocalUtils.java Thu Oct 23 02:26:32 2008
@@ -0,0 +1,224 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.util;
+
+import java.lang.ref.WeakReference;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Utility functions related to ThreadLocals.
+ * This class provides utilities for managing the lifecycles of ThreadLocals.
+ * In particular, many application servers do not clean up the ThreadLocals
+ * added to the request thread before returning the request thread to
+ * its thread pool.  This may have several severe side-effects, including
+ * <ol>
+ *   <li>Leakage of objects referenced by the thread local</li>
+ *   <li>Possible security holes if the ThreadLocals contents are reused
+ *       on a request for a different user.</li>
+ *   <li>Leakage of the entire class loader in live patching scenarios</li>
+ *   <li>ClassCastExceptions in live patching scenarios</li>
+ * </ol>
+ * To avoid these problems, this class provides utilities for creating
+ * and registering ThreadLocals that will be removed from the thread
+ * automatically at the end of the current request.
+ * @see #newRequestThreadLocal
+ * @see #registerRequestThreadLocal
+ */
+public final class ThreadLocalUtils
+{
+  /**
+   * Integration interface implemented by object holding onto ThreadLocals
+   * with a specified lifetime
+   * @see ThreadLocalLifecycle
+   */
+  public static abstract class ThreadLocalManager
+  {
+    /**
+     * Called by the ThreadLocalLifeCycle when the ThreadLocals managed by
+     * this ThreadLocalManager need to be cleaned up by removing their
+     * instances from the current Thread.
+     */
+    public abstract void removeThreadLocals();
+  }
+  
+  /**
+   * Integration interface implemented by an object that cleans up the
+   * ThreadLocals in a ThreadLocalManager with the specified lifetime.
+   * The ThreadLocalLifecycle cleans up the ThreadLocals by calling
+   * <code>removeThreadLocals</code> on the ThreadLocalManager passed
+   * to it in <code>init</code> at the appropriate time.
+   * @see ThreadLocalManager
+   * @see #init
+   */
+  public static abstract class ThreadLocalLifecycle
+  {
+    /**
+     * Called after instantiating the ThreadLocalLifecycle so that the
+     * ThreadLocalLifecycle can clean up the ThreadLocalManager at the
+     * appropriate moment.
+     * @param manager Manager of ThreadLocals that will be cleaned up by
+     * this ThreadLocalLifecycle.
+     * @see ThreadLocalManager#removeThreadLocals
+     */
+    public abstract void init(ThreadLocalManager manager);
+  }
+  
+  // don't allow instantiation 
+  private ThreadLocalUtils()
+  {
+  }
+
+  /**
+   * Creates and returns a new ThreadLocal that will be automatically removed from
+   * the each request thread when the request finishes.
+   * @return The ThreadLocal
+   * @see #registerRequestThreadLocal
+   */
+  public static <T> ThreadLocal<T> newRequestThreadLocal()
+  {
+    return registerRequestThreadLocal(new ThreadLocal<T>());
+  }
+
+  /**
+   * Registers and returns the ThreadLocal to be automatically removed from
+   * the each request thread when the request finishes.
+   * @param threadLocal ThreadLocal to register for automatic removal
+   * @return The reigistered ThreadLocal
+   * @see #newRequestThreadLocal
+   */
+  public static <T> ThreadLocal<T> registerRequestThreadLocal(ThreadLocal<T> threadLocal)
+  {
+    return _getThreadLocalManager(_REQUEST_SERVICE).registerThreadLocal(threadLocal);
+  }
+  
+  /**
+   * Returns the ResettableThreadLocalManager for the specified threadLocalGroup name.  If no
+   * ResettableThreadLocalManager is currently registered for the threadLocalGroup, one will
+   * be instantiated, its related ThreadLocalLifecycle instantiated and the ThreadLocalManager
+   * registered with the ThreadLocalLifecycle
+   * @param threadLocalGroup Identifier for this group
+   * @return the ResettableThreadLocalManager for this threadLocalGroup name
+   */
+  private static ResettableThreadLocalManager _getThreadLocalManager(String threadLocalGroup)
+  {
+    // see if we already have a ResettableThreadLocalManager registered
+    ResettableThreadLocalManager threadLocalManager = _threadLocalManagers.get(threadLocalGroup);
+    
+    // if we don't, create one
+    if (threadLocalManager == null)
+    {
+      threadLocalManager = new ResettableThreadLocalManager();
+      
+      // handle simultaneous registration
+      ResettableThreadLocalManager oldThreadLocalManager =
+                            _threadLocalManagers.putIfAbsent(threadLocalGroup, threadLocalManager);
+      
+      if (oldThreadLocalManager != null)
+      {
+        // simultaneous registration, use the one that was registered first
+        threadLocalManager = oldThreadLocalManager;
+      }
+      else
+      {
+        // find the ThreadLocalLifecycle for this threadLocalGroup by looking in
+        // META-INF/Services, instantiate it and register ourselves with it so that we
+        // can be cleaned up
+        List<ThreadLocalLifecycle> lifecycles = ClassLoaderUtils.getServices(threadLocalGroup);
+        
+        if (!lifecycles.isEmpty())
+        {
+          lifecycles.get(0).init(threadLocalManager);
+        }
+      }
+    }
+    
+    return threadLocalManager;
+  }
+  
+  /**
+   * ThreadLocalManager implementation class
+   */
+  private static class ResettableThreadLocalManager extends ThreadLocalManager
+  {
+    public ResettableThreadLocalManager()
+    {
+      // create the list of resettable ThreadLocals for this group
+      _threadLocals = new CopyOnWriteArrayList<WeakReference<ThreadLocal<?>>>();
+    }
+    
+    /**
+     * Registers the ThreadLocal for cleanup when this ThreadLocalManager is cleaned up
+     * @param threadLocal ThreadLocal to register for clean up
+     * @return The registered ThreadLocal
+     */
+    public <T> ThreadLocal<T> registerThreadLocal(ThreadLocal<T> threadLocal)
+    {
+      if (threadLocal == null)
+        throw new NullPointerException();
+      
+      // WeakReference might be overkill here, but make sure we don't pin ThreadLocals
+      _threadLocals.add(new WeakReference<ThreadLocal<?>>(threadLocal));
+      
+      return threadLocal;
+    }
+    
+    /**
+     * Called by the ThreadLocalLifecycle to clean up all of the ThreadLocals registered
+     * with this ThreadLocalManager
+     */
+    public void removeThreadLocals()
+    {
+      Iterator<WeakReference<ThreadLocal<?>>> iterator = _threadLocals.iterator();
+      
+      while (iterator.hasNext())
+      {
+        ThreadLocal<?> threadLocal = iterator.next().get();
+        
+        if (threadLocal == null)
+        {
+          // the threadLocal has been released, so remove this entry.  It will be
+          // readded if the ThreadLocal is ever recreated
+          iterator.remove();
+        }
+        else
+        {
+          // reset the threadlocal for this thread
+          threadLocal.remove();
+        }
+      }
+    }
+    
+    private final Collection<WeakReference<ThreadLocal<?>>> _threadLocals;
+  }
+
+  // Name used for the request-scoped ThreadLocalManager
+  private static final String _REQUEST_SERVICE = ThreadLocalUtils.class.getName() + 
+                                                                    ".ThreadLocalLifecycle.REQUEST";
+  
+  // threadLocalGroup -> ThreadLocalManager Map
+  private static final ConcurrentMap<String, ResettableThreadLocalManager>_threadLocalManagers
+                     = new ConcurrentHashMap<String, ResettableThreadLocalManager>();
+}

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/GlobalConfiguratorImpl.java Thu Oct 23 02:26:32 2008
@@ -23,6 +23,8 @@
 import java.util.List;
 import java.util.Map;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 import javax.faces.context.ExternalContext;
 
 import javax.servlet.ServletRequest;
@@ -383,6 +385,19 @@
   }
 
   /**
+   * Hackily called by the ThreadLocalResetter to register itself so that the
+   * GlobalConfiguratorImpl can tell the ThreadLocalResetter to clean up the
+   * ThreadLocals at the appropriate time.
+   */
+  void __setThreadLocalResetter(ThreadLocalResetter resetter)
+  {
+    if (resetter == null)
+      throw new NullPointerException();
+    
+    _threadResetter.set(resetter);
+  }
+    
+  /**
    * @param externalContext
    * @return
    */
@@ -401,6 +416,10 @@
         _LOG.warning("REQUESTCONTEXT_NOT_PROPERLY_RELEASED");
       }
       context.release();
+      ThreadLocalResetter resetter = _threadResetter.get();
+      
+      if (resetter != null)
+        resetter.__removeRequestThreadLocals();
     }
 
     // See if we've got a cached RequestContext instance; if so,
@@ -440,6 +459,13 @@
     {
       context.release();
       assert RequestContext.getCurrentInstance() == null;
+
+      // now that the request is over, clean up all of the request-scoped
+      // ThreadLocals.
+      ThreadLocalResetter resetter = _threadResetter.get();
+      
+      if (resetter != null)
+        resetter.__removeRequestThreadLocals();
     }
   }
 
@@ -719,6 +745,10 @@
       ".TEST_PARAM";
   }
 
+  // hacky reference to the ThreadLocalResetter used to clean up request-scoped
+  // ThreadLocals
+  private AtomicReference<ThreadLocalResetter> _threadResetter = 
+                                                        new AtomicReference<ThreadLocalResetter>();
 
   static private final TrinidadLogger _LOG =
     TrinidadLogger.createTrinidadLogger(GlobalConfiguratorImpl.class);

Added: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ThreadLocalResetter.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ThreadLocalResetter.java?rev=707325&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ThreadLocalResetter.java (added)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/ThreadLocalResetter.java Thu Oct 23 02:26:32 2008
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidadinternal.config;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalLifecycle;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalManager;
+
+/**
+ * Implementation of ThreadLocalLifecycle for request-scoped ThreadLocals, registered
+ * through META-INF/SERVICES.  This class cooperates with GlobalConfiguratorImpl in order
+ * to ensure that the request-scoped ThreadLocals are cleaned up at the end of each
+ * request.
+ */
+public class ThreadLocalResetter extends ThreadLocalLifecycle
+{
+  /**
+   * All class to be instatiated through reflection
+   */
+  public ThreadLocalResetter()
+  {
+  }
+  
+  /**
+   * Called by ThreadLocalUtils after instantiating the ThreadLocalResetter in order to
+   * pass the ThreadLocalManager to use to clean up the request-scoped ThreadLocals.
+   */
+  public void init(ThreadLocalManager manager)
+  {
+    if (manager == null)
+      throw new NullPointerException();
+    
+    // save the ThreadLocalManager to use to clean up the request-scoped ThreadLocals 
+    _threadLocalManager.set(manager);
+    
+    // slam a reference to our instance on the GlobalConfiguratorImpl so that it can
+    // call __removeRequestThreadLocals when the request is finished 
+    GlobalConfiguratorImpl.getInstance().__setThreadLocalResetter(this);
+  }
+  
+  /**
+   * Called by the GlobalConfiguratorImpl when the request is finished so that the
+   * ThreadLocalResetter can ask the ThreadLocalManager to clean itself up
+   */
+  void __removeRequestThreadLocals()
+  {
+    ThreadLocalManager threadLocalManager = _threadLocalManager.get();
+    
+    if (threadLocalManager != null)
+    {
+      // clean up all of the request-scoped ThreadLocals
+      threadLocalManager.removeThreadLocals();
+    }
+  }
+
+  // ThreadLocalManager to clean up
+  private AtomicReference<ThreadLocalManager> _threadLocalManager = new 
+                                                   AtomicReference<ThreadLocalManager>();
+}

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuUtils.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuUtils.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/menu/MenuUtils.java Thu Oct 23 02:26:32 2008
@@ -33,11 +33,12 @@
 import javax.faces.webapp.UIComponentTag;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
 
 /**
  * Menu Utilities used by the Menu Model internal code.
  * All classes are package private.
- * 
+ *
  */
 class MenuUtils
 {
@@ -299,7 +300,7 @@
   @SuppressWarnings("unchecked")
   static void loadBundle(String resBundleName, String resBundleKey)
   {
-    ThreadLocal<String> bundleKey = new ThreadLocal<String>();
+    ThreadLocal<String> bundleKey = ThreadLocalUtils.newRequestThreadLocal();
     
     bundleKey.set(resBundleKey);    
     loadBundle(resBundleName, bundleKey);
@@ -455,3 +456,4 @@
 
 
 
+

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/table/TableRenderingContext.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/table/TableRenderingContext.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/table/TableRenderingContext.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/table/TableRenderingContext.java Thu Oct 23 02:26:32 2008
@@ -32,6 +32,7 @@
 import org.apache.myfaces.trinidad.model.RowKeySet;
 import org.apache.myfaces.trinidad.context.RenderingContext;
 import org.apache.myfaces.trinidad.render.CoreRenderer;
+import org.apache.myfaces.trinidad.util.ThreadLocalUtils;
 import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.SkinSelectors;
 import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.XhtmlRenderer;
 import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.XhtmlUtils;
@@ -597,5 +598,5 @@
 
 
   static private final ThreadLocal<TableRenderingContext> _CURRENT_CONTEXT = 
-    new ThreadLocal<TableRenderingContext>();
+    ThreadLocalUtils.newRequestThreadLocal();
 }

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/webapp/TrinidadFilterImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/webapp/TrinidadFilterImpl.java?rev=707325&r1=707324&r2=707325&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/webapp/TrinidadFilterImpl.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/webapp/TrinidadFilterImpl.java Thu Oct 23 02:26:32 2008
@@ -288,11 +288,7 @@
     "org.apache.myfaces.trinidadinternal.webapp.AdfacesFilterImpl.EXECUTED";
 
   private static ThreadLocal<PseudoFacesContext> _PSEUDO_FACES_CONTEXT = 
-    new ThreadLocal<PseudoFacesContext>()
-  {
-    @Override
-    protected PseudoFacesContext initialValue() { return null; }
-  };
+    new ThreadLocal<PseudoFacesContext>();
 
   private static final TrinidadLogger _LOG =
     TrinidadLogger.createTrinidadLogger(TrinidadFilterImpl.class);

Added: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalLifecycle.REQUEST
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalLifecycle.REQUEST?rev=707325&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalLifecycle.REQUEST (added)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.util.ThreadLocalUtils.ThreadLocalLifecycle.REQUEST Thu Oct 23 02:26:32 2008
@@ -0,0 +1 @@
+org.apache.myfaces.trinidadinternal.config.ThreadLocalResetter