]> source.dussan.org Git - vaadin-framework.git/commitdiff
Unify ThreadLocal handling (#9469)
authorLeif Åstrand <leif@vaadin.com>
Tue, 4 Sep 2012 11:08:41 +0000 (14:08 +0300)
committerLeif Åstrand <leif@vaadin.com>
Wed, 5 Sep 2012 08:39:33 +0000 (11:39 +0300)
server/src/com/vaadin/Application.java
server/src/com/vaadin/server/PortletApplicationContext2.java
server/src/com/vaadin/server/ServletApplicationContext.java
server/src/com/vaadin/server/VaadinPortlet.java
server/src/com/vaadin/server/VaadinServlet.java
server/src/com/vaadin/ui/UI.java
server/src/com/vaadin/util/CurrentInstance.java [new file with mode: 0644]
uitest/src/com/vaadin/tests/application/ThreadLocalInstances.html

index d2313c0566f67d2378f6e8189f596441d1e215f7..088934c5f9030219216f541aa4f2b6ba5a2c3d6d 100644 (file)
@@ -70,6 +70,7 @@ import com.vaadin.ui.AbstractField;
 import com.vaadin.ui.Table;
 import com.vaadin.ui.UI;
 import com.vaadin.ui.Window;
+import com.vaadin.util.CurrentInstance;
 import com.vaadin.util.ReflectTools;
 
 /**
@@ -1798,13 +1799,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
         return Collections.unmodifiableCollection(requestHandlers);
     }
 
-    /**
-     * Thread local for keeping track of currently used application instance
-     * 
-     * @since 7.0
-     */
-    private static final ThreadLocal<Application> currentApplication = new ThreadLocal<Application>();
-
     /**
      * Gets the currently used application. The current application is
      * automatically defined when processing requests to the server. In other
@@ -1819,7 +1813,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
      * @since 7.0
      */
     public static Application getCurrent() {
-        return currentApplication.get();
+        return CurrentInstance.get(Application.class);
     }
 
     /**
@@ -1840,7 +1834,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
      * @since 7.0
      */
     public static void setCurrent(Application application) {
-        currentApplication.set(application);
+        CurrentInstance.setInheritable(Application.class, application);
     }
 
     /**
index 3efcc91c0812666c2039c4a4da712717ed27bf70..6a12eafc471bc835bdbc4976c0c3606fdc2cc9df 100644 (file)
@@ -46,6 +46,7 @@ import javax.xml.namespace.QName;
 
 import com.vaadin.Application;
 import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
 
 /**
  * TODO Write documentation, fix JavaDoc tags.
@@ -153,8 +154,9 @@ public class PortletApplicationContext2 extends ApplicationContext {
     }
 
     private PortletResponse getCurrentResponse() {
-        WrappedPortletResponse currentResponse = VaadinPortlet
-                .getCurrentResponse();
+        WrappedPortletResponse currentResponse = (WrappedPortletResponse) CurrentInstance
+                .get(WrappedResponse.class);
+
         if (currentResponse != null) {
             return currentResponse.getPortletResponse();
         } else {
@@ -163,8 +165,10 @@ public class PortletApplicationContext2 extends ApplicationContext {
     }
 
     public PortletConfig getPortletConfig() {
-        return VaadinPortlet.getCurrentResponse().getDeploymentConfiguration()
-                .getPortlet().getPortletConfig();
+        WrappedPortletResponse response = (WrappedPortletResponse) CurrentInstance
+                .get(WrappedResponse.class);
+        return response.getDeploymentConfiguration().getPortlet()
+                .getPortletConfig();
     }
 
     public void addPortletListener(Application app, PortletListener listener) {
index ecf6202917360f1b9cbe350adc3a25acd1c450f3..4184b68de488f4ae4d4b03acb61cb6509ed83823 100644 (file)
@@ -25,6 +25,7 @@ import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionBindingListener;
 
 import com.vaadin.Application;
+import com.vaadin.util.CurrentInstance;
 
 /**
  * Web application context for Vaadin applications.
@@ -84,7 +85,8 @@ public class ServletApplicationContext extends ApplicationContext {
         reinitializingSession = false;
 
         // Create a new session
-        HttpSession newSession = VaadinServlet.getCurrentRequest().getSession();
+        HttpSession newSession = WrappedHttpServletRequest.cast(
+                CurrentInstance.get(WrappedRequest.class)).getSession();
 
         // Restores all attributes (security key, reference to this context
         // instance)
index 199b8e1fc127058fe10e6aa3b28a1cdca55b7b4b..0a996447354853027ba1b9bfe8791b0f6a64e85f 100644 (file)
@@ -57,6 +57,7 @@ import com.vaadin.Application.ApplicationStartEvent;
 import com.vaadin.server.AbstractCommunicationManager.Callback;
 import com.vaadin.server.ServletPortletHelper.ApplicationClassException;
 import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
 
 /**
  * Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0
@@ -296,8 +297,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
     private PortletDeploymentConfiguration deploymentConfiguration;
     private AddonContext addonContext;
 
-    private static ThreadLocal<WrappedPortletResponse> currentResponse = new ThreadLocal<WrappedPortletResponse>();
-
     @Override
     public void init(PortletConfig config) throws PortletException {
         super.init(config);
@@ -395,10 +394,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
         return deploymentConfiguration.isProductionMode();
     }
 
-    public static WrappedPortletResponse getCurrentResponse() {
-        return currentResponse.get();
-    }
-
     protected void handleRequest(PortletRequest request,
             PortletResponse response) throws PortletException, IOException {
         RequestTimer requestTimer = new RequestTimer();
@@ -412,7 +407,8 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
         WrappedPortletResponse wrappedResponse = new WrappedPortletResponse(
                 response, getDeploymentConfiguration());
 
-        currentResponse.set(wrappedResponse);
+        CurrentInstance.set(WrappedRequest.class, wrappedRequest);
+        CurrentInstance.set(WrappedResponse.class, wrappedResponse);
 
         RequestType requestType = getRequestType(wrappedRequest);
 
@@ -608,9 +604,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
 
                         }
                     } finally {
-                        UI.setCurrent(null);
-                        Application.setCurrent(null);
-                        currentResponse.set(null);
+                        CurrentInstance.clearAll();
 
                         PortletSession session = request
                                 .getPortletSession(false);
index 078263c623d628f3ad1cda9e40d6638d60e335e5..81569030e7df963c5a2a46af6fa243ba0b345f19 100644 (file)
@@ -50,6 +50,7 @@ import com.vaadin.server.AbstractCommunicationManager.Callback;
 import com.vaadin.server.ServletPortletHelper.ApplicationClassException;
 import com.vaadin.shared.ApplicationConstants;
 import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
 
 @SuppressWarnings("serial")
 public class VaadinServlet extends HttpServlet implements Constants {
@@ -157,8 +158,6 @@ public class VaadinServlet extends HttpServlet implements Constants {
         }
     }
 
-    private static ThreadLocal<WrappedHttpServletRequest> currentRequest = new ThreadLocal<WrappedHttpServletRequest>();
-
     // TODO Move some (all?) of the constants to a separate interface (shared
     // with portlet)
 
@@ -263,17 +262,14 @@ public class VaadinServlet extends HttpServlet implements Constants {
         service(createWrappedRequest(request), createWrappedResponse(response));
     }
 
-    public static WrappedHttpServletRequest getCurrentRequest() {
-        return currentRequest.get();
-    }
-
     private void service(WrappedHttpServletRequest request,
             WrappedHttpServletResponse response) throws ServletException,
             IOException {
         RequestTimer requestTimer = new RequestTimer();
         requestTimer.start();
 
-        currentRequest.set(request);
+        CurrentInstance.set(WrappedResponse.class, response);
+        CurrentInstance.set(WrappedRequest.class, request);
 
         AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper(
                 this);
@@ -423,9 +419,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
                                 .onRequestEnd(request, response);
                     }
                 } finally {
-                    UI.setCurrent(null);
-                    Application.setCurrent(null);
-                    currentRequest.set(null);
+                    CurrentInstance.clearAll();
 
                     HttpSession session = request.getSession(false);
                     if (session != null) {
index 7ae4e6bda34450e92c7f6439fe108cb50470f968..e016e9432c1657726cc68622d31b850dcfb7672d 100644 (file)
@@ -49,6 +49,7 @@ import com.vaadin.shared.ui.BorderStyle;
 import com.vaadin.shared.ui.ui.UIConstants;
 import com.vaadin.shared.ui.ui.UIServerRpc;
 import com.vaadin.shared.ui.ui.UIState;
+import com.vaadin.util.CurrentInstance;
 import com.vaadin.util.ReflectTools;
 
 /**
@@ -450,11 +451,6 @@ public abstract class UI extends AbstractComponentContainer implements
      */
     protected ActionManager actionManager;
 
-    /**
-     * Thread local for keeping track of the current UI.
-     */
-    private static final ThreadLocal<UI> currentUI = new ThreadLocal<UI>();
-
     /** Identifies the click event */
     private ConnectorTracker connectorTracker = new ConnectorTracker(this);
 
@@ -982,7 +978,7 @@ public abstract class UI extends AbstractComponentContainer implements
      * @see ThreadLocal
      */
     public static void setCurrent(UI ui) {
-        currentUI.set(ui);
+        CurrentInstance.setInheritable(UI.class, ui);
     }
 
     /**
@@ -995,7 +991,7 @@ public abstract class UI extends AbstractComponentContainer implements
      * @see #setCurrent(UI)
      */
     public static UI getCurrent() {
-        return currentUI.get();
+        return CurrentInstance.get(UI.class);
     }
 
     public void setScrollTop(int scrollTop) {
diff --git a/server/src/com/vaadin/util/CurrentInstance.java b/server/src/com/vaadin/util/CurrentInstance.java
new file mode 100644 (file)
index 0000000..8478ba9
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ * 
+ * Licensed 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 com.vaadin.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * Keeps track of various thread local instances used by the framework.
+ * 
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+public class CurrentInstance {
+    private final Object instance;
+    private final boolean inheritable;
+
+    private static InheritableThreadLocal<Map<Class<?>, CurrentInstance>> instances = new InheritableThreadLocal<Map<Class<?>, CurrentInstance>>() {
+        @Override
+        protected Map<Class<?>, CurrentInstance> childValue(
+                Map<Class<?>, CurrentInstance> parentValue) {
+            Map<Class<?>, CurrentInstance> value = new HashMap<Class<?>, CurrentInstance>();
+
+            // Copy all inheritable values to child map
+            for (Entry<Class<?>, CurrentInstance> e : parentValue.entrySet()) {
+                if (e.getValue().inheritable) {
+                    value.put(e.getKey(), e.getValue());
+                }
+            }
+
+            return value;
+        }
+
+        @Override
+        protected Map<java.lang.Class<?>, CurrentInstance> initialValue() {
+            return new HashMap<Class<?>, CurrentInstance>();
+        }
+    };
+
+    private CurrentInstance(Object instance, boolean inheritable) {
+        this.instance = instance;
+        this.inheritable = inheritable;
+    }
+
+    /**
+     * Gets the current instance of a specific type if available.
+     * 
+     * @param type
+     *            the class to get an instance of
+     * @return the current instance or the provided type, or <code>null</code>
+     *         if there is no current instance.
+     */
+    public static <T> T get(Class<T> type) {
+        CurrentInstance currentInstance = instances.get().get(type);
+        if (currentInstance != null) {
+            return type.cast(currentInstance.instance);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the current instance of the given type.
+     * 
+     * @see #setInheritable(Class, Object)
+     * @see ThreadLocal
+     * 
+     * @param type
+     *            the class that should be used when getting the current
+     *            instance back
+     * @param instance
+     *            the actual instance
+     */
+    public static <T> void set(Class<T> type, T instance) {
+        set(type, instance, false);
+    }
+
+    /**
+     * Sets the current inheritable instance of the given type. A current
+     * instance that is inheritable will be available for child threads.
+     * 
+     * @see #set(Class, Object)
+     * @see InheritableThreadLocal
+     * 
+     * @param type
+     *            the class that should be used when getting the current
+     *            instance back
+     * @param instance
+     *            the actual instance
+     */
+    public static <T> void setInheritable(Class<T> type, T instance) {
+        set(type, instance, true);
+    }
+
+    private static <T> void set(Class<T> type, T instance, boolean inheritable) {
+        if (instance == null) {
+            instances.get().remove(type);
+        } else {
+            assert type.isInstance(instance) : "Invald instance type";
+            CurrentInstance previousInstance = instances.get().put(type,
+                    new CurrentInstance(instance, inheritable));
+            if (previousInstance != null) {
+                assert previousInstance.inheritable == inheritable : "Inheritable status mismatch for "
+                        + type;
+            }
+        }
+    }
+
+    /**
+     * Clears all current instances.
+     */
+    public static void clearAll() {
+        instances.get().clear();
+    }
+}
index 35657c73fc0bf129f9a2d7333ab91498899c83bd..b7fbca4c040e53f3397f2f5b89394e59b8065f4a 100644 (file)
 <tr>
        <td>assertText</td>
        <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_5</td>
-       <td>11. null app in background thread</td>
+       <td>11. this app in background thread</td>
 </tr>
 <tr>
        <td>assertText</td>
        <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_4</td>
-       <td>12. null root in background thread</td>
+       <td>12. this root in background thread</td>
 </tr>
 <tr>
        <td>assertText</td>
@@ -94,7 +94,7 @@
 <tr>
        <td>assertText</td>
        <td>vaadin=runcomvaadintestsapplicationThreadLocalInstances::PID_SLog_row_2</td>
-       <td>14. null root in resource handler</td>
+       <td>14. this root in resource handler</td>
 </tr>
 <tr>
        <td>assertText</td>