From c1e82529b1191d9c41de0dc8a4cde8caf9754329 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Wed, 19 Sep 2012 12:19:30 +0300 Subject: [PATCH] Add some getCurrent() methods (#9505) This change also clears the current instances in the beginning of each request in case something has accidentally been left uncleared in a previous request on the same thread. --- .../server/AbstractCommunicationManager.java | 2 + .../src/com/vaadin/server/VaadinPortlet.java | 63 ++++++++++++++- .../src/com/vaadin/server/VaadinService.java | 79 +++++++++++++++++++ .../src/com/vaadin/server/VaadinServlet.java | 64 ++++++++++++++- .../vaadin/server/VaadinServletSession.java | 11 ++- .../AttachShouldBeCalledForSubWindows.java | 4 +- .../resources/NonExistingFileResource.java | 9 +-- .../com/vaadin/tests/tickets/Ticket1975.java | 7 +- .../vaadin/tests/util/SampleDirectory.java | 6 +- 9 files changed, 222 insertions(+), 23 deletions(-) diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java index a0a59da0ec..9ac33df7d2 100644 --- a/server/src/com/vaadin/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java @@ -84,6 +84,7 @@ import com.vaadin.ui.ConnectorTracker; import com.vaadin.ui.HasComponents; import com.vaadin.ui.UI; import com.vaadin.ui.Window; +import com.vaadin.util.CurrentInstance; /** * This is a common base class for the server-side implementations of the @@ -2469,6 +2470,7 @@ public abstract class AbstractCommunicationManager implements Serializable { assert UI.getCurrent() == null; CombinedRequest combinedRequest = new CombinedRequest(request); + CurrentInstance.set(WrappedRequest.class, combinedRequest); response.setContentType("application/json; charset=UTF-8"); diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index 30d897c6bc..1462db5899 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -222,6 +222,19 @@ public class VaadinPortlet extends GenericPortlet implements Constants { return new PortletCommunicationManager(session); } + public static WrappedPortletRequest getCurrentRequest() { + WrappedRequest currentRequest = VaadinService.getCurrentRequest(); + try { + return WrappedPortletRequest.cast(currentRequest); + } catch (ClassCastException e) { + return null; + } + } + + public static WrappedPortletResponse getCurrentResponse() { + return (WrappedPortletResponse) VaadinService.getCurrentResponse(); + } + } public static class WrappedHttpAndPortletRequest extends @@ -377,6 +390,8 @@ public class VaadinPortlet extends GenericPortlet implements Constants { @Override public void init(PortletConfig config) throws PortletException { + CurrentInstance.clearAll(); + setCurrent(this); super.init(config); Properties initParameters = new Properties(); @@ -397,11 +412,14 @@ public class VaadinPortlet extends GenericPortlet implements Constants { DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(initParameters); vaadinService = createPortletService(deploymentConfiguration); + // Sets current service even though there are no request and response + vaadinService.setCurrentInstances(null, null); addonContext = new AddonContext(vaadinService); addonContext.init(); portletInitialized(); + CurrentInstance.clearAll(); } protected void portletInitialized() { @@ -499,6 +517,9 @@ public class VaadinPortlet extends GenericPortlet implements Constants { RequestTimer requestTimer = new RequestTimer(); requestTimer.start(); + CurrentInstance.clearAll(); + setCurrent(this); + AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( this); @@ -507,8 +528,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( response, getVaadinService()); - CurrentInstance.set(WrappedRequest.class, wrappedRequest); - CurrentInstance.set(WrappedResponse.class, wrappedResponse); + getVaadinService().setCurrentInstances(wrappedRequest, wrappedResponse); RequestType requestType = getRequestType(wrappedRequest); @@ -928,4 +948,43 @@ public class VaadinPortlet extends GenericPortlet implements Constants { return Logger.getLogger(VaadinPortlet.class.getName()); } + /** + * Gets the currently used Vaadin portlet. The current portlet is + * automatically defined when initializing the portlet and when processing + * requests to the server and in threads started at a point when the current + * portlet is defined (see {@link InheritableThreadLocal}). In other cases, + * (e.g. from background threads started in some other way), the current + * portlet is not automatically defined. + * + * @return the current vaadin portlet instance if available, otherwise + * null + * + * @see #setCurrent(VaadinPortlet) + * + * @since 7.0 + */ + public static VaadinPortlet getCurrent() { + return CurrentInstance.get(VaadinPortlet.class); + } + + /** + * Sets the current Vaadin portlet. This method is used by the framework to + * set the current portlet whenever a new request is processed and it is + * cleared when the request has been processed. + *

+ * The application developer can also use this method to define the current + * portlet outside the normal request handling, e.g. when initiating custom + * background threads. + *

+ * + * @param portlet + * the Vaadin portlet to register as the current portlet + * + * @see #getCurrent() + * @see InheritableThreadLocal + */ + public static void setCurrent(VaadinPortlet portlet) { + CurrentInstance.setInheritable(VaadinPortlet.class, portlet); + } + } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 5f3f47adba..80590df4a0 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -34,6 +34,7 @@ import com.vaadin.LegacyApplication; import com.vaadin.event.EventRouter; import com.vaadin.server.ServletPortletHelper.ApplicationClassException; import com.vaadin.server.VaadinSession.SessionStartEvent; +import com.vaadin.util.CurrentInstance; import com.vaadin.util.ReflectTools; /** @@ -447,4 +448,82 @@ public abstract class VaadinService implements Serializable { * for the request; else false */ protected abstract boolean requestCanCreateSession(WrappedRequest request); + + /** + * Gets the currently used Vaadin service. The current service is + * automatically defined when processing requests related to the service and + * in threads started at a point when the current service is defined (see + * {@link InheritableThreadLocal}). In other cases, (e.g. from background + * threads started in some other way), the current service is not + * automatically defined. + * + * @return the current Vaadin service instance if available, otherwise + * null + * + * @see #setCurrentInstances(WrappedRequest, WrappedResponse) + */ + public static VaadinService getCurrent() { + return CurrentInstance.get(VaadinService.class); + } + + /** + * Sets the this Vaadin service as the current service and also sets the + * current wrapped request and wrapped response. This method is used by the + * framework to set the current instances when a request related to the + * service is processed and they are cleared when the request has been + * processed. + *

+ * The application developer can also use this method to define the current + * instances outside the normal request handling, e.g. when initiating + * custom background threads. + *

+ * + * @param request + * the wrapped request to set as the current request, or + * null if no request should be set. + * @param response + * the wrapped response to set as the current response, or + * null if no response should be set. + * + * @see #getCurrent() + * @see #getCurrentRequest() + * @see #getCurrentResponse() + */ + public void setCurrentInstances(WrappedRequest request, + WrappedResponse response) { + CurrentInstance.setInheritable(VaadinService.class, this); + CurrentInstance.set(WrappedRequest.class, request); + CurrentInstance.set(WrappedResponse.class, response); + } + + /** + * Gets the currently processed wrapped request. The current request is + * automatically defined when the request is started. The current request + * can not be used in e.g. background threads because of the way server + * implementations reuse request instances. + * + * @return the current wrapped request instance if available, otherwise + * null + * + * @see #setCurrentInstances(WrappedRequest, WrappedResponse) + */ + public static WrappedRequest getCurrentRequest() { + return CurrentInstance.get(WrappedRequest.class); + } + + /** + * Gets the currently processed wrapped request. The current request is + * automatically defined when the request is started. The current request + * can not be used in e.g. background threads because of the way server + * implementations reuse request instances. + * + * @return the current wrapped request instance if available, otherwise + * null + * + * @see #setCurrentInstances(WrappedRequest, WrappedResponse) + */ + public static WrappedResponse getCurrentResponse() { + return CurrentInstance.get(WrappedResponse.class); + } + } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index f83477c9bc..1d92151288 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -197,6 +197,20 @@ public class VaadinServlet extends HttpServlet implements Constants { VaadinSession session) { return new CommunicationManager(session); } + + public static WrappedHttpServletRequest getCurrentRequest() { + WrappedRequest currentRequest = VaadinService.getCurrentRequest(); + try { + return WrappedHttpServletRequest.cast(currentRequest); + } catch (ClassCastException e) { + return null; + } + } + + public static WrappedHttpServletResponse getCurrentResponse() { + return (WrappedHttpServletResponse) VaadinService + .getCurrentResponse(); + } } private static class AbstractApplicationServletWrapper implements Callback { @@ -241,6 +255,8 @@ public class VaadinServlet extends HttpServlet implements Constants { @Override public void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException { + CurrentInstance.clearAll(); + setCurrent(this); super.init(servletConfig); Properties initParameters = new Properties(); @@ -262,17 +278,60 @@ public class VaadinServlet extends HttpServlet implements Constants { DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(initParameters); servletService = createServletService(deploymentConfiguration); + // Sets current service even though there are no request and response + servletService.setCurrentInstances(null, null); addonContext = new AddonContext(servletService); addonContext.init(); servletInitialized(); + + CurrentInstance.clearAll(); } protected void servletInitialized() { // Empty by default } + /** + * Gets the currently used Vaadin servlet. The current servlet is + * automatically defined when initializing the servlet and when processing + * requests to the server and in threads started at a point when the current + * servlet is defined (see {@link InheritableThreadLocal}). In other cases, + * (e.g. from background threads started in some other way), the current + * servlet is not automatically defined. + * + * @return the current Vaadin servlet instance if available, otherwise + * null + * + * @see #setCurrent(VaadinServlet) + * + * @since 7.0 + */ + public static VaadinServlet getCurrent() { + return CurrentInstance.get(VaadinServlet.class); + } + + /** + * Sets the current Vaadin servlet. This method is used by the framework to + * set the current servlet whenever a new request is processed and it is + * cleared when the request has been processed. + *

+ * The application developer can also use this method to define the current + * servlet outside the normal request handling, e.g. when initiating custom + * background threads. + *

+ * + * @param servlet + * the Vaadin servlet to register as the current servlet + * + * @see #getCurrent() + * @see InheritableThreadLocal + */ + public static void setCurrent(VaadinServlet servlet) { + CurrentInstance.setInheritable(VaadinServlet.class, servlet); + } + protected DeploymentConfiguration createDeploymentConfiguration( Properties initParameters) { return new DefaultDeploymentConfiguration(getClass(), initParameters); @@ -310,6 +369,8 @@ public class VaadinServlet extends HttpServlet implements Constants { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + CurrentInstance.clearAll(); + setCurrent(this); service(createWrappedRequest(request), createWrappedResponse(response)); } @@ -319,8 +380,7 @@ public class VaadinServlet extends HttpServlet implements Constants { RequestTimer requestTimer = new RequestTimer(); requestTimer.start(); - CurrentInstance.set(WrappedResponse.class, response); - CurrentInstance.set(WrappedRequest.class, request); + getVaadinService().setCurrentInstances(request, response); AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( this); diff --git a/server/src/com/vaadin/server/VaadinServletSession.java b/server/src/com/vaadin/server/VaadinServletSession.java index b2e3b9f54c..b2dc84d857 100644 --- a/server/src/com/vaadin/server/VaadinServletSession.java +++ b/server/src/com/vaadin/server/VaadinServletSession.java @@ -23,7 +23,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; -import com.vaadin.util.CurrentInstance; +import com.vaadin.server.VaadinServlet.ServletService; /** * Web application context for Vaadin applications. @@ -58,6 +58,12 @@ public class VaadinServletSession extends VaadinSession { * to avoid session fixation attacks. */ public void reinitializeSession() { + WrappedHttpServletRequest currentRequest = ServletService + .getCurrentRequest(); + if (currentRequest == null) { + throw new IllegalStateException( + "Can not reinitialize session outside normal request handling."); + } HttpSession oldSession = getHttpSession(); @@ -77,8 +83,7 @@ public class VaadinServletSession extends VaadinSession { reinitializingSession = false; // Create a new session - HttpSession newSession = WrappedHttpServletRequest.cast( - CurrentInstance.get(WrappedRequest.class)).getSession(); + HttpSession newSession = currentRequest.getSession(); // Restores all attributes (security key, reference to this context // instance) diff --git a/uitest/src/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java b/uitest/src/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java index 6f21346b7d..4d0dea4f91 100644 --- a/uitest/src/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java +++ b/uitest/src/com/vaadin/tests/components/window/AttachShouldBeCalledForSubWindows.java @@ -1,6 +1,7 @@ package com.vaadin.tests.components.window; import com.vaadin.event.ShortcutAction.KeyCode; +import com.vaadin.server.VaadinService; import com.vaadin.server.WrappedRequest; import com.vaadin.tests.components.AbstractTestCase; import com.vaadin.tests.util.Log; @@ -11,7 +12,6 @@ import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.UI; import com.vaadin.ui.Window; -import com.vaadin.util.CurrentInstance; public class AttachShouldBeCalledForSubWindows extends AbstractTestCase { private static final long serialVersionUID = 1L; @@ -23,7 +23,7 @@ public class AttachShouldBeCalledForSubWindows extends AbstractTestCase { @Override public void init() { - WrappedRequest request = CurrentInstance.get(WrappedRequest.class); + WrappedRequest request = VaadinService.getCurrentRequest(); if (request.getParameter("attachMainFirst") != null) { addSubWindowBeforeMainWindow = false; } else { diff --git a/uitest/src/com/vaadin/tests/resources/NonExistingFileResource.java b/uitest/src/com/vaadin/tests/resources/NonExistingFileResource.java index c102291b50..f55c1f1f1d 100644 --- a/uitest/src/com/vaadin/tests/resources/NonExistingFileResource.java +++ b/uitest/src/com/vaadin/tests/resources/NonExistingFileResource.java @@ -3,11 +3,10 @@ package com.vaadin.tests.resources; import java.io.File; import com.vaadin.server.FileResource; -import com.vaadin.server.WrappedRequest; +import com.vaadin.server.VaadinService; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.util.CurrentInstance; public class NonExistingFileResource extends TestBase { @@ -26,10 +25,8 @@ public class NonExistingFileResource extends TestBase { @Override public void buttonClick(ClickEvent event) { - FileResource res = new FileResource(new File(CurrentInstance - .get(WrappedRequest.class).getVaadinService() - .getBaseDirectory() - + "/" + filename)); + FileResource res = new FileResource(new File(VaadinService + .getCurrent().getBaseDirectory() + "/" + filename)); getMainWindow().open(res); } diff --git a/uitest/src/com/vaadin/tests/tickets/Ticket1975.java b/uitest/src/com/vaadin/tests/tickets/Ticket1975.java index a688fd9908..f41585ff5d 100644 --- a/uitest/src/com/vaadin/tests/tickets/Ticket1975.java +++ b/uitest/src/com/vaadin/tests/tickets/Ticket1975.java @@ -5,14 +5,13 @@ import java.io.File; import java.io.FileInputStream; import com.vaadin.LegacyApplication; -import com.vaadin.server.WrappedRequest; +import com.vaadin.server.VaadinService; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.CustomLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.UI.LegacyWindow; -import com.vaadin.util.CurrentInstance; public class Ticket1975 extends LegacyApplication { @@ -47,8 +46,8 @@ public class Ticket1975 extends LegacyApplication { } })); - File baseDir = CurrentInstance.get(WrappedRequest.class) - .getVaadinService().getBaseDirectory().getAbsoluteFile(); + File baseDir = VaadinService.getCurrent().getBaseDirectory() + .getAbsoluteFile(); File f = new File(baseDir + "/VAADIN/themes/" + getTheme() + "/layouts/Ticket1975.html"); diff --git a/uitest/src/com/vaadin/tests/util/SampleDirectory.java b/uitest/src/com/vaadin/tests/util/SampleDirectory.java index 140f778551..5c45e0d64e 100644 --- a/uitest/src/com/vaadin/tests/util/SampleDirectory.java +++ b/uitest/src/com/vaadin/tests/util/SampleDirectory.java @@ -19,13 +19,12 @@ package com.vaadin.tests.util; import java.io.File; import com.vaadin.server.SystemError; +import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinSession; -import com.vaadin.server.WrappedRequest; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.UI; -import com.vaadin.util.CurrentInstance; /** * Provides sample directory based on application directory. If this fails then @@ -48,8 +47,7 @@ public class SampleDirectory { + "context base directory failed, " + "possible security constraint with Application " + "Server or Servlet Container.
"; - File file = CurrentInstance.get(WrappedRequest.class) - .getVaadinService().getBaseDirectory(); + File file = VaadinService.getCurrent().getBaseDirectory(); if ((file == null) || (!file.canRead()) || (file.getAbsolutePath() == null)) { // cannot access example directory, possible security issue with -- 2.39.5