From 0a64a44e5fc9e7f79d5540aefd39262d50424477 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Leif=20=C3=85strand?= Date: Wed, 5 Sep 2012 10:42:27 +0300 Subject: [PATCH] Only support one Application per session (#9402) --- .../com/vaadin/server/ApplicationContext.java | 71 +++++++++++-------- .../server/PortletApplicationContext2.java | 37 ---------- .../server/ServletApplicationContext.java | 27 ------- .../src/com/vaadin/server/VaadinPortlet.java | 18 ++--- .../src/com/vaadin/server/VaadinServlet.java | 47 +++++------- .../application/ApplicationCloseTest.java | 7 +- 6 files changed, 71 insertions(+), 136 deletions(-) diff --git a/server/src/com/vaadin/server/ApplicationContext.java b/server/src/com/vaadin/server/ApplicationContext.java index 85a77241d9..0b317486e4 100644 --- a/server/src/com/vaadin/server/ApplicationContext.java +++ b/server/src/com/vaadin/server/ApplicationContext.java @@ -16,10 +16,6 @@ package com.vaadin.server; import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; import java.util.logging.Level; import java.util.logging.Logger; @@ -43,11 +39,11 @@ import com.vaadin.Application; public abstract class ApplicationContext implements HttpSessionBindingListener, Serializable { - protected final HashSet applications = new HashSet(); + private Application application; protected WebBrowser browser = new WebBrowser(); - protected HashMap applicationToAjaxAppMgrMap = new HashMap(); + private AbstractCommunicationManager communicationManager; private long totalSessionTime = 0; @@ -70,22 +66,7 @@ public abstract class ApplicationContext implements HttpSessionBindingListener, public void valueUnbound(HttpSessionBindingEvent event) { // If we are going to be unbound from the session, the session must be // closing - try { - while (!applications.isEmpty()) { - final Application app = applications.iterator().next(); - app.close(); - removeApplication(app); - } - } catch (Exception e) { - // This should never happen but is possible with rare - // configurations (e.g. robustness tests). If you have one - // thread doing HTTP socket write and another thread trying to - // remove same application here. Possible if you got e.g. session - // lifetime 1 min but socket write may take longer than 1 min. - // FIXME: Handle exception - getLogger().log(Level.SEVERE, - "Could not remove application, leaking memory.", e); - } + removeApplication(); } /** @@ -102,19 +83,36 @@ public abstract class ApplicationContext implements HttpSessionBindingListener, } /** - * Returns a collection of all the applications in this context. + * Returns the applications in this context. * - * Each application context contains all active applications for one user. + * Each application context contains the application for one user. * - * @return A collection containing all the applications in this context. + * @return The application of this context, or null if there is + * no application */ - public Collection getApplications() { - return Collections.unmodifiableCollection(applications); + public Application getApplication() { + return application; } - protected void removeApplication(Application application) { - applications.remove(application); - applicationToAjaxAppMgrMap.remove(application); + public void removeApplication() { + if (application == null) { + return; + } + try { + application.close(); + } catch (Exception e) { + // This should never happen but is possible with rare + // configurations (e.g. robustness tests). If you have one + // thread doing HTTP socket write and another thread trying to + // remove same application here. Possible if you got e.g. session + // lifetime 1 min but socket write may take longer than 1 min. + // FIXME: Handle exception + getLogger().log(Level.SEVERE, + "Could not close application, leaking memory.", e); + } finally { + application = null; + communicationManager = null; + } } /** @@ -168,4 +166,17 @@ public abstract class ApplicationContext implements HttpSessionBindingListener, this.session = session; } + public AbstractCommunicationManager getApplicationManager() { + return communicationManager; + } + + public void setApplication(Application application, + AbstractCommunicationManager communicationManager) { + if (this.application != null) { + removeApplication(); + } + this.application = application; + this.communicationManager = communicationManager; + } + } \ No newline at end of file diff --git a/server/src/com/vaadin/server/PortletApplicationContext2.java b/server/src/com/vaadin/server/PortletApplicationContext2.java index f157dc9ae6..63f02ac4ec 100644 --- a/server/src/com/vaadin/server/PortletApplicationContext2.java +++ b/server/src/com/vaadin/server/PortletApplicationContext2.java @@ -57,32 +57,12 @@ public class PortletApplicationContext2 extends ApplicationContext { protected Map> portletListeners = new HashMap>(); - protected HashMap portletWindowIdToApplicationMap = new HashMap(); - private final Map eventActionDestinationMap = new HashMap(); private final Map eventActionValueMap = new HashMap(); private final Map sharedParameterActionNameMap = new HashMap(); private final Map sharedParameterActionValueMap = new HashMap(); - protected PortletCommunicationManager getApplicationManager( - Application application) { - PortletCommunicationManager mgr = (PortletCommunicationManager) applicationToAjaxAppMgrMap - .get(application); - - if (mgr == null) { - // Creates a new manager - mgr = createPortletCommunicationManager(application); - applicationToAjaxAppMgrMap.put(application, mgr); - } - return mgr; - } - - protected PortletCommunicationManager createPortletCommunicationManager( - Application application) { - return new PortletCommunicationManager(application); - } - public static PortletApplicationContext2 getApplicationContext( PortletSession session) { Object cxattr = session.getAttribute(PortletApplicationContext2.class @@ -103,23 +83,6 @@ public class PortletApplicationContext2 extends ApplicationContext { return cx; } - @Override - protected void removeApplication(Application application) { - super.removeApplication(application); - // values() is backed by map, removes the key-value pair from the map - portletWindowIdToApplicationMap.values().remove(application); - } - - protected void addApplication(Application application, - String portletWindowId) { - applications.add(application); - portletWindowIdToApplicationMap.put(portletWindowId, application); - } - - public Application getApplicationForWindowId(String portletWindowId) { - return portletWindowIdToApplicationMap.get(portletWindowId); - } - public PortletSession getPortletSession() { WrappedSession wrappedSession = getSession(); PortletSession session = ((WrappedPortletSession) wrappedSession) diff --git a/server/src/com/vaadin/server/ServletApplicationContext.java b/server/src/com/vaadin/server/ServletApplicationContext.java index 910051a26b..a1f5a81624 100644 --- a/server/src/com/vaadin/server/ServletApplicationContext.java +++ b/server/src/com/vaadin/server/ServletApplicationContext.java @@ -23,7 +23,6 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; -import com.vaadin.Application; import com.vaadin.util.CurrentInstance; /** @@ -125,30 +124,4 @@ public class ServletApplicationContext extends ApplicationContext { cx.setSession(new WrappedHttpSession(session)); return cx; } - - protected void addApplication(Application application) { - applications.add(application); - } - - /** - * Gets communication manager for an application. - * - * If this application has not been running before, a new manager is - * created. - * - * @param application - * @return CommunicationManager - */ - public CommunicationManager getApplicationManager(Application application, - VaadinServlet servlet) { - CommunicationManager mgr = (CommunicationManager) applicationToAjaxAppMgrMap - .get(application); - - if (mgr == null) { - // Creates new manager - mgr = servlet.createCommunicationManager(application); - applicationToAjaxAppMgrMap.put(application, mgr); - } - return mgr; - } } diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index 5fb2340bc8..2bec4249ed 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -478,8 +478,8 @@ public class VaadinPortlet extends GenericPortlet implements Constants { PortletApplicationContext2 applicationContext = getApplicationContext(request .getPortletSession()); - PortletCommunicationManager applicationManager = applicationContext - .getApplicationManager(application); + PortletCommunicationManager applicationManager = (PortletCommunicationManager) applicationContext + .getApplicationManager(); if (requestType == RequestType.CONNECTOR_RESOURCE) { applicationManager.serveConnectorResource(wrappedRequest, @@ -805,7 +805,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { throws IOException { final PortletSession session = request.getPortletSession(); if (session != null) { - getApplicationContext(session).removeApplication(application); + getApplicationContext(session).removeApplication(); } // Do not send any redirects when running inside a portlet. } @@ -863,16 +863,17 @@ public class VaadinPortlet extends GenericPortlet implements Constants { application.close(); if (session != null) { PortletApplicationContext2 context = getApplicationContext(session); - context.removeApplication(application); + context.removeApplication(); } } private Application createApplication(PortletRequest request) - throws PortletException, MalformedURLException { + throws PortletException { Application newApplication = getNewApplication(request); final PortletApplicationContext2 context = getApplicationContext(request .getPortletSession()); - context.addApplication(newApplication, request.getWindowID()); + context.setApplication(newApplication, new PortletCommunicationManager( + newApplication)); return newApplication; } @@ -888,8 +889,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { } PortletApplicationContext2 context = getApplicationContext(session); - Application application = context.getApplicationForWindowId(request - .getWindowID()); + Application application = context.getApplication(); if (application == null) { return null; } @@ -897,7 +897,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { return application; } // application found but not running - context.removeApplication(application); + context.removeApplication(); return null; } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 62fb8ba71e..af66a3496e 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -31,7 +31,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; -import java.util.Iterator; import java.util.Locale; import java.util.Properties; import java.util.logging.Level; @@ -322,8 +321,8 @@ public class VaadinServlet extends HttpServlet implements Constants { */ ServletApplicationContext webApplicationContext = getApplicationContext(request .getSession()); - CommunicationManager applicationManager = webApplicationContext - .getApplicationManager(application, this); + CommunicationManager applicationManager = (CommunicationManager) webApplicationContext + .getApplicationManager(); if (requestType == RequestType.CONNECTOR_RESOURCE) { applicationManager.serveConnectorResource(request, response); @@ -726,7 +725,8 @@ public class VaadinServlet extends HttpServlet implements Constants { final ServletApplicationContext context = getApplicationContext(request .getSession()); - context.addApplication(newApplication); + context.setApplication(newApplication, + createCommunicationManager(newApplication)); return newApplication; } @@ -1334,30 +1334,19 @@ public class VaadinServlet extends HttpServlet implements Constants { ServletApplicationContext context = getApplicationContext(session); - // Gets application list for the session. - final Collection applications = context.getApplications(); - - // Search for the application (using the application URI) from the list - for (final Iterator i = applications.iterator(); i - .hasNext();) { - final Application sessionApplication = i.next(); - final String sessionApplicationPath = sessionApplication.getURL() - .getPath(); - String requestApplicationPath = getApplicationUrl(request) - .getPath(); - - if (requestApplicationPath.equals(sessionApplicationPath)) { - // Found a running application - if (sessionApplication.isRunning()) { - return sessionApplication; - } - // Application has stopped, so remove it before creating a new - // application - getApplicationContext(session).removeApplication( - sessionApplication); - break; - } + Application sessionApplication = context.getApplication(); + + if (sessionApplication == null) { + return null; + } + + if (sessionApplication.isRunning()) { + // Found a running application + return sessionApplication; } + // Application has stopped, so remove it before creating a new + // application + getApplicationContext(session).removeApplication(); // Existing application not found return null; @@ -1386,7 +1375,7 @@ public class VaadinServlet extends HttpServlet implements Constants { final HttpSession session = request.getSession(); if (session != null) { - getApplicationContext(session).removeApplication(application); + getApplicationContext(session).removeApplication(); } response.sendRedirect(response.encodeRedirectURL(logoutUrl)); @@ -1439,7 +1428,7 @@ public class VaadinServlet extends HttpServlet implements Constants { application.close(); if (session != null) { ServletApplicationContext context = getApplicationContext(session); - context.removeApplication(application); + context.removeApplication(); } } diff --git a/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java b/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java index 1f5f0dc691..f2fe90f4b1 100644 --- a/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java +++ b/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java @@ -1,6 +1,5 @@ package com.vaadin.tests.application; -import com.vaadin.Application; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.tests.components.TestBase; import com.vaadin.ui.Button; @@ -15,9 +14,9 @@ public class ApplicationCloseTest extends TestBase { protected void setup() { Label applications = new Label("Applications in session:
", ContentMode.XHTML); - for (Application a : getContext().getApplications()) { - applications.setValue(applications.getValue() + "App: " + a - + "
"); + if (getContext().getApplication() != null) { + applications.setValue(applications.getValue() + "App: " + + getContext().getApplication() + "
"); } applications.setValue(applications.getValue() + "

"); -- 2.39.5