diff options
author | Artur Signell <artur@vaadin.com> | 2013-03-22 17:31:26 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-04-02 07:39:28 +0000 |
commit | 7dcccb01754a42338ec056cfda642bd8c28bb4d7 (patch) | |
tree | f1477f29413d3e44feca32448278f1ca3f10acb3 /server | |
parent | d7708c5cc6c0a260598d373abe79024f5e5ee078 (diff) | |
download | vaadin-framework-7dcccb01754a42338ec056cfda642bd8c28bb4d7.tar.gz vaadin-framework-7dcccb01754a42338ec056cfda642bd8c28bb4d7.zip |
Correctly set thread locals when session times out (#11361, #10995)
Change-Id: I5051cef344f03af276be24a28471a6d6c15b0da6
Diffstat (limited to 'server')
-rw-r--r-- | server/src/com/vaadin/server/VaadinService.java | 42 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/server/VaadinSessionTest.java | 115 |
2 files changed, 147 insertions, 10 deletions
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index baa455e69e..20d87d6554 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -340,18 +340,40 @@ public abstract class VaadinService implements Serializable { SESSION_DESTROY_METHOD); } + /** + * Handles destruction of the given session. Internally ensures proper + * locking is done. + * + * @param vaadinSession + * The session to destroy + */ public void fireSessionDestroy(VaadinSession vaadinSession) { - for (UI ui : new ArrayList<UI>(vaadinSession.getUIs())) { - // close() called here for consistency so that it is always called - // before a UI is removed. UI.isClosing() is thus always true in - // UI.detach() and associated detach listeners. - if (!ui.isClosing()) { - ui.close(); + final VaadinSession session = vaadinSession; + session.runSafely(new Runnable() { + @Override + public void run() { + ArrayList<UI> uis = new ArrayList<UI>(session.getUIs()); + for (final UI ui : uis) { + ui.runSafely(new Runnable() { + @Override + public void run() { + /* + * close() called here for consistency so that it is + * always called before a UI is removed. + * UI.isClosing() is thus always true in UI.detach() + * and associated detach listeners. + */ + if (!ui.isClosing()) { + ui.close(); + } + session.removeUI(ui); + } + }); + } + eventRouter.fireEvent(new SessionDestroyEvent( + VaadinService.this, session)); } - vaadinSession.removeUI(ui); - } - - eventRouter.fireEvent(new SessionDestroyEvent(this, vaadinSession)); + }); } /** diff --git a/server/tests/src/com/vaadin/server/VaadinSessionTest.java b/server/tests/src/com/vaadin/server/VaadinSessionTest.java new file mode 100644 index 0000000000..6cad3307bf --- /dev/null +++ b/server/tests/src/com/vaadin/server/VaadinSessionTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2000-2013 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.server; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReentrantLock; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionBindingEvent; + +import junit.framework.Assert; + +import org.easymock.EasyMock; +import org.junit.Test; + +import com.vaadin.server.ClientConnector.DetachEvent; +import com.vaadin.server.ClientConnector.DetachListener; +import com.vaadin.ui.UI; + +public class VaadinSessionTest { + + @Test + public void threadLocalsAfterUnderlyingSessionTimeout() { + + final VaadinServlet mockServlet = new VaadinServlet() { + @Override + public String getServletName() { + return "mockServlet"; + }; + }; + + final VaadinServletService mockService = new VaadinServletService( + mockServlet, EasyMock.createMock(DeploymentConfiguration.class)); + + HttpSession mockHttpSession = EasyMock.createMock(HttpSession.class); + WrappedSession mockWrappedSession = new WrappedHttpSession( + mockHttpSession) { + final ReentrantLock lock = new ReentrantLock(); + + @Override + public Object getAttribute(String name) { + if ("mockServlet.lock".equals(name)) { + return lock; + } + return super.getAttribute(name); + } + }; + + final VaadinSession session = new VaadinSession(mockService); + session.storeInSession(mockService, mockWrappedSession); + + final UI ui = new UI() { + Page page = new Page(this) { + @Override + public void init(VaadinRequest request) { + } + }; + + @Override + protected void init(VaadinRequest request) { + } + + @Override + public Page getPage() { + return page; + } + }; + VaadinServletRequest vaadinRequest = new VaadinServletRequest( + EasyMock.createMock(HttpServletRequest.class), mockService) { + @Override + public String getParameter(String name) { + if ("theme".equals(name)) { + return null; + } + + return super.getParameter(name); + } + }; + + ui.doInit(vaadinRequest, session.getNextUIid()); + + ui.setSession(session); + session.addUI(ui); + + final AtomicBoolean detachCalled = new AtomicBoolean(false); + ui.addDetachListener(new DetachListener() { + @Override + public void detach(DetachEvent event) { + detachCalled.set(true); + Assert.assertEquals(ui, UI.getCurrent()); + Assert.assertEquals(ui.getPage(), Page.getCurrent()); + Assert.assertEquals(session, VaadinSession.getCurrent()); + Assert.assertEquals(mockService, VaadinService.getCurrent()); + Assert.assertEquals(mockServlet, VaadinServlet.getCurrent()); + } + }); + + session.valueUnbound(EasyMock.createMock(HttpSessionBindingEvent.class)); + Assert.assertTrue(detachCalled.get()); + } +} |