diff options
author | Leif Åstrand <leif@vaadin.com> | 2012-09-20 13:52:22 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2012-09-20 13:52:37 +0300 |
commit | 6b28dc7bf41b8590fcab3d60afd5aa407f1f1401 (patch) | |
tree | 9f11e412e2dce3d6b495d29a9c954a70603aa036 /server | |
parent | d66d9b3f5d3a85fb8016eb75ae68267d50244cd9 (diff) | |
download | vaadin-framework-6b28dc7bf41b8590fcab3d60afd5aa407f1f1401.tar.gz vaadin-framework-6b28dc7bf41b8590fcab3d60afd5aa407f1f1401.zip |
Refactor how LegacyApplication and VaadinSession are "closed" (#9635)
Diffstat (limited to 'server')
11 files changed, 473 insertions, 341 deletions
diff --git a/server/src/com/vaadin/LegacyApplication.java b/server/src/com/vaadin/LegacyApplication.java index 3a6ffaa39c..3925c0b077 100644 --- a/server/src/com/vaadin/LegacyApplication.java +++ b/server/src/com/vaadin/LegacyApplication.java @@ -22,16 +22,13 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.DefaultErrorListener; import com.vaadin.server.Terminal.ErrorEvent; import com.vaadin.server.Terminal.ErrorListener; import com.vaadin.server.VaadinSession; -import com.vaadin.server.WrappedRequest; import com.vaadin.ui.UI; +import com.vaadin.ui.UI.LegacyWindow; /** * A special application designed to help migrating applications from Vaadin 6 @@ -45,19 +42,20 @@ import com.vaadin.ui.UI; * @since 7.0 */ @Deprecated -public abstract class LegacyApplication extends AbstractUIProvider implements - ErrorListener { - /** - * Ignore initial / and then get everything up to the next / - */ - private static final Pattern WINDOW_NAME_PATTERN = Pattern - .compile("^/?([^/]+).*"); - +public abstract class LegacyApplication implements ErrorListener { private UI.LegacyWindow mainWindow; private String theme; private Map<String, UI.LegacyWindow> legacyUINames = new HashMap<String, UI.LegacyWindow>(); + private boolean isRunning = true; + + /** + * URL where the user is redirected to on application close, or null if + * application is just closed without redirection. + */ + private String logoutURL = null; + /** * Sets the main window of this application. Setting window as a main window * of this application also adds the window to this application. @@ -69,9 +67,7 @@ public abstract class LegacyApplication extends AbstractUIProvider implements if (this.mainWindow != null) { throw new IllegalStateException("mainWindow has already been set"); } - if (mainWindow.getSession() == null) { - mainWindow.setSession(VaadinSession.getCurrent()); - } else if (mainWindow.getSession() != VaadinSession.getCurrent()) { + if (mainWindow.getSession() != null) { throw new IllegalStateException( "mainWindow is attached to another application"); } @@ -80,7 +76,7 @@ public abstract class LegacyApplication extends AbstractUIProvider implements // no current UI -> set the main window as the current UI UI.setCurrent(mainWindow); } - mainWindow.setApplication(this); + addWindow(mainWindow); this.mainWindow = mainWindow; } @@ -91,36 +87,6 @@ public abstract class LegacyApplication extends AbstractUIProvider implements protected abstract void init(); - @Override - public Class<? extends UI> getUIClass(WrappedRequest request) { - UI uiInstance = getUIInstance(request); - if (uiInstance != null) { - return uiInstance.getClass(); - } - return null; - } - - @Override - public UI createInstance(WrappedRequest request, Class<? extends UI> type) { - return getUIInstance(request); - } - - @Override - public String getTheme(WrappedRequest request, Class<? extends UI> uiClass) { - return theme; - } - - @Override - public String getPageTitle(WrappedRequest request, - Class<? extends UI> uiClass) { - UI uiInstance = getUIInstance(request); - if (uiInstance != null) { - return uiInstance.getCaption(); - } else { - return super.getPageTitle(request, uiClass); - } - } - /** * Gets the mainWindow of the application. * @@ -138,43 +104,6 @@ public abstract class LegacyApplication extends AbstractUIProvider implements return mainWindow; } - private UI getUIInstance(WrappedRequest request) { - String pathInfo = request.getRequestPathInfo(); - String name = null; - if (pathInfo != null && pathInfo.length() > 0) { - Matcher matcher = WINDOW_NAME_PATTERN.matcher(pathInfo); - if (matcher.matches()) { - // Skip the initial slash - name = matcher.group(1); - } - } - UI.LegacyWindow window = getWindow(name); - if (window != null) { - return window; - } - return mainWindow; - } - - /** - * This implementation simulates the way of finding a window for a request - * by extracting a window name from the requested path and passes that name - * to {@link #getWindow(String)}. - * <p> - * {@inheritDoc} - */ - @Override - public UI getExistingUI(WrappedRequest request) { - UI uiInstance = getUIInstance(request); - if (uiInstance.getUIId() == -1) { - // Not initialized -> Let go through createUIInstance to make it - // initialized - return null; - } else { - UI.setCurrent(uiInstance); - return uiInstance; - } - } - /** * Sets the application's theme. * <p> @@ -289,15 +218,64 @@ public abstract class LegacyApplication extends AbstractUIProvider implements return VaadinSession.getCurrent(); } - protected void close() { - VaadinSession.getCurrent().close(); + public void close() { + isRunning = false; + Collection<LegacyWindow> windows = getWindows(); + for (LegacyWindow legacyWindow : windows) { + String logoutUrl = getLogoutURL(); + if (logoutUrl == null) { + URL url = getURL(); + if (url != null) { + logoutUrl = url.toString(); + } + } + if (logoutUrl != null) { + legacyWindow.getPage().setLocation(logoutUrl); + } + legacyWindow.getSession().cleanupUI(legacyWindow); + } } public boolean isRunning() { - return VaadinSession.getCurrent().isRunning(); + return isRunning; } public URL getURL() { return VaadinSession.getCurrent().getURL(); } + + /** + * Returns the URL user is redirected to on application close. If the URL is + * <code>null</code>, the application is closed normally as defined by the + * application running environment. + * <p> + * Desktop application just closes the application window and + * web-application redirects the browser to application main URL. + * </p> + * + * @return the URL. + * + * @deprecated might be refactored or removed before 7.0.0 + */ + @Deprecated + public String getLogoutURL() { + return logoutURL; + } + + /** + * Sets the URL user is redirected to on application close. If the URL is + * <code>null</code>, the application is closed normally as defined by the + * application running environment: Desktop application just closes the + * application window and web-application redirects the browser to + * application main URL. + * + * @param logoutURL + * the logoutURL to set. + * + * @deprecated might be refactored or removed before 7.0.0 + */ + @Deprecated + public void setLogoutURL(String logoutURL) { + this.logoutURL = logoutURL; + } }
\ No newline at end of file diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java index 9ac33df7d2..b7d0b98ab8 100644 --- a/server/src/com/vaadin/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java @@ -83,6 +83,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.ConnectorTracker; import com.vaadin.ui.HasComponents; import com.vaadin.ui.UI; +import com.vaadin.ui.UI.LegacyWindow; import com.vaadin.ui.Window; import com.vaadin.util.CurrentInstance; @@ -576,18 +577,11 @@ public abstract class AbstractCommunicationManager implements Serializable { session.getLock().lock(); try { - // Finds the UI within the session - if (session.isRunning()) { - // Returns if no window found - if (uI == null) { - // This should not happen, no windows exists but - // session is still open. - getLogger().warning("Could not get UI for session"); - return; - } - } else { - // session has been closed - endApplication(request, response, session); + // Verify that there's an UI + if (uI == null) { + // This should not happen, no windows exists but + // session is still open. + getLogger().warning("Could not get UI for session"); return; } @@ -653,6 +647,16 @@ public abstract class AbstractCommunicationManager implements Serializable { * */ protected void postPaint(UI uI) { + if (uI instanceof LegacyWindow) { + LegacyWindow legacyWindow = (LegacyWindow) uI; + if (!legacyWindow.getApplication().isRunning()) { + // Detach LegacyWindow if it belongs to a closed + // LegacyApplication + legacyWindow.setApplication(null); + legacyWindow.setSession(null); + } + } + // Remove connectors that have been detached from the session during // handling of the request uI.getConnectorTracker().cleanConnectorMap(); @@ -752,13 +756,6 @@ public abstract class AbstractCommunicationManager implements Serializable { WrappedResponse response, Callback callback, boolean repaintAll, final PrintWriter outWriter, UI uI, boolean analyzeLayouts) throws PaintException, IOException, JSONException { - - // Removes session if it has stopped during variable changes - if (!session.isRunning()) { - endApplication(request, response, session); - return; - } - openJsonMessage(outWriter, response); // security key @@ -2177,45 +2174,6 @@ public abstract class AbstractCommunicationManager implements Serializable { outWriter.print("]"); // Close locales } - /** - * Ends the Application. - * - * The browser is redirected to the Application logout URL set with - * {@link VaadinSession#setLogoutURL(String)}, or to the application URL if - * no logout URL is given. - * - * @param request - * the request instance. - * @param response - * the response to write to. - * @param application - * the Application to end. - * @throws IOException - * if the writing failed due to input/output error. - */ - private void endApplication(WrappedRequest request, - WrappedResponse response, VaadinSession application) - throws IOException { - - String logoutUrl = application.getLogoutURL(); - if (logoutUrl == null) { - logoutUrl = application.getURL().toString(); - } - // clients JS app is still running, send a special json file to tell - // client that application has quit and where to point browser now - // Set the response type - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - openJsonMessage(outWriter, response); - outWriter.print("\"redirect\":{"); - outWriter.write("\"url\":\"" + logoutUrl + "\"}"); - closeJsonMessage(outWriter); - outWriter.flush(); - outWriter.close(); - out.flush(); - } - protected void closeJsonMessage(PrintWriter outWriter) { outWriter.print("}]"); } diff --git a/server/src/com/vaadin/server/LegacyApplicationUIProvider.java b/server/src/com/vaadin/server/LegacyApplicationUIProvider.java new file mode 100644 index 0000000000..c0f64088b4 --- /dev/null +++ b/server/src/com/vaadin/server/LegacyApplicationUIProvider.java @@ -0,0 +1,134 @@ +/* + * 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.server; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.vaadin.LegacyApplication; +import com.vaadin.ui.UI; + +public abstract class LegacyApplicationUIProvider extends AbstractUIProvider { + /** + * Ignore initial / and then get everything up to the next / + */ + private static final Pattern WINDOW_NAME_PATTERN = Pattern + .compile("^/?([^/]+).*"); + + @Override + public Class<? extends UI> getUIClass(WrappedRequest request) { + UI uiInstance = getUIInstance(request); + if (uiInstance != null) { + return uiInstance.getClass(); + } + return null; + } + + @Override + public UI createInstance(WrappedRequest request, Class<? extends UI> type) { + return getUIInstance(request); + } + + @Override + public String getTheme(WrappedRequest request, Class<? extends UI> uiClass) { + LegacyApplication application = getApplication(); + if (application != null) { + return application.getTheme(); + } else { + return null; + } + } + + @Override + public String getPageTitle(WrappedRequest request, + Class<? extends UI> uiClass) { + UI uiInstance = getUIInstance(request); + if (uiInstance != null) { + return uiInstance.getCaption(); + } else { + return super.getPageTitle(request, uiClass); + } + } + + private UI getUIInstance(WrappedRequest request) { + String pathInfo = request.getRequestPathInfo(); + String name = null; + if (pathInfo != null && pathInfo.length() > 0) { + Matcher matcher = WINDOW_NAME_PATTERN.matcher(pathInfo); + if (matcher.matches()) { + // Skip the initial slash + name = matcher.group(1); + } + } + + LegacyApplication application = getApplication(); + if (application == null) { + return null; + } + UI.LegacyWindow window = application.getWindow(name); + if (window != null) { + return window; + } + return application.getMainWindow(); + } + + /** + * This implementation simulates the way of finding a window for a request + * by extracting a window name from the requested path and passes that name + * to {@link #getWindow(String)}. + * <p> + * {@inheritDoc} + */ + @Override + public UI getExistingUI(WrappedRequest request) { + UI uiInstance = getUIInstance(request); + if (uiInstance == null || uiInstance.getUIId() == -1) { + // Not initialized -> Let go through createUIInstance to make it + // initialized + return null; + } else { + UI.setCurrent(uiInstance); + return uiInstance; + } + } + + private LegacyApplication getApplication() { + LegacyApplication application = VaadinSession.getCurrent() + .getAttribute(LegacyApplication.class); + if (application == null) { + application = createApplication(); + if (application == null) { + return null; + } + VaadinSession.getCurrent().setAttribute(LegacyApplication.class, + application); + application.doInit(); + } + + if (application != null && !application.isRunning()) { + VaadinSession.getCurrent().setAttribute(LegacyApplication.class, + null); + // Run again without a current application + return getApplication(); + } + + return application; + } + + protected abstract LegacyApplication createApplication(); + +} diff --git a/server/src/com/vaadin/server/LegacyVaadinPortlet.java b/server/src/com/vaadin/server/LegacyVaadinPortlet.java index bdc03ff643..ef59615a29 100644 --- a/server/src/com/vaadin/server/LegacyVaadinPortlet.java +++ b/server/src/com/vaadin/server/LegacyVaadinPortlet.java @@ -24,6 +24,26 @@ import com.vaadin.server.ServletPortletHelper.ApplicationClassException; public class LegacyVaadinPortlet extends VaadinPortlet { + private static final LegacyApplicationUIProvider provider = new LegacyApplicationUIProvider() { + @Override + protected LegacyApplication createApplication() { + VaadinPortlet portlet = VaadinPortlet.getCurrent(); + if (portlet instanceof LegacyVaadinPortlet) { + LegacyVaadinPortlet legacyPortlet = (LegacyVaadinPortlet) portlet; + PortletRequest request = PortletService + .getCurrentPortletRequest(); + if (legacyPortlet.shouldCreateApplication(request)) { + try { + return legacyPortlet.getNewApplication(request); + } catch (PortletException e) { + throw new RuntimeException(e); + } + } + } + return null; + } + }; + @Override public void init() throws PortletException { super.init(); @@ -68,21 +88,10 @@ public class LegacyVaadinPortlet extends VaadinPortlet { private void onVaadinSessionStarted(WrappedPortletRequest request, VaadinPortletSession session) throws PortletException { - if (shouldCreateApplication(request)) { - // Must set current before running init() - VaadinSession.setCurrent(session); - - // XXX Must update details here so they are available in init. - session.getBrowser().updateRequestDetails(request); - - LegacyApplication legacyApplication = getNewApplication(request - .getPortletRequest()); - legacyApplication.doInit(); - session.addUIProvider(legacyApplication); - } + session.addUIProvider(provider); } - protected boolean shouldCreateApplication(WrappedPortletRequest request) { + protected boolean shouldCreateApplication(PortletRequest request) { return true; } } diff --git a/server/src/com/vaadin/server/LegacyVaadinServlet.java b/server/src/com/vaadin/server/LegacyVaadinServlet.java index 8d55fddc39..d9c84309fb 100644 --- a/server/src/com/vaadin/server/LegacyVaadinServlet.java +++ b/server/src/com/vaadin/server/LegacyVaadinServlet.java @@ -25,6 +25,27 @@ import com.vaadin.server.ServletPortletHelper.ApplicationClassException; public class LegacyVaadinServlet extends VaadinServlet { + private static final UIProvider provider = new LegacyApplicationUIProvider() { + @Override + protected LegacyApplication createApplication() { + + VaadinServlet servlet = VaadinServlet.getCurrent(); + if (servlet instanceof LegacyVaadinServlet) { + LegacyVaadinServlet legacyServlet = (LegacyVaadinServlet) servlet; + HttpServletRequest request = ServletService + .getCurrentServletRequest(); + try { + if (legacyServlet.shouldCreateApplication(request)) { + return legacyServlet.getNewApplication(request); + } + } catch (ServletException e) { + throw new RuntimeException(e); + } + } + return null; + } + }; + @Override public void init(ServletConfig servletConfig) throws ServletException { super.init(servletConfig); @@ -65,27 +86,14 @@ public class LegacyVaadinServlet extends VaadinServlet { } } - protected boolean shouldCreateApplication(WrappedHttpServletRequest request) + protected boolean shouldCreateApplication(HttpServletRequest request) throws ServletException { return true; } private void onVaadinSessionStarted(WrappedRequest wrappedRequest, VaadinSession session) throws ServletException { - WrappedHttpServletRequest request = WrappedHttpServletRequest - .cast(wrappedRequest); - - if (shouldCreateApplication(request)) { - // Must set current before running init() - VaadinSession.setCurrent(session); - - // XXX Must update details here so they are available in init. - session.getBrowser().updateRequestDetails(request); - - LegacyApplication legacyApplication = getNewApplication(request); - legacyApplication.doInit(); - session.addUIProvider(legacyApplication); - } + session.addUIProvider(provider); } } diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index e9bd3a08cf..074c2aa9cc 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -612,34 +612,29 @@ public class VaadinPortlet extends GenericPortlet implements Constants { UI uI = null; application.getLock().lock(); try { - if (application.isRunning()) { - switch (requestType) { - case RENDER: - case ACTION: - // Both action requests and render requests are - // ok - // without a UI as they render the initial HTML - // and then do a second request - uI = application - .getUIForRequest(wrappedRequest); - break; - case BROWSER_DETAILS: - // Should not try to find a UI here as the - // combined request details might change the UI - break; - case FILE_UPLOAD: - // no window - break; - case APPLICATION_RESOURCE: - // use main window - should not need any window - // UI = application.getUI(); - break; - default: - uI = application - .getUIForRequest(wrappedRequest); - } - // if window not found, not a problem - use null + switch (requestType) { + case RENDER: + case ACTION: + // Both action requests and render requests are ok + // without a UI as they render the initial HTML + // and then do a second request + uI = application.getUIForRequest(wrappedRequest); + break; + case BROWSER_DETAILS: + // Should not try to find a UI here as the + // combined request details might change the UI + break; + case FILE_UPLOAD: + // no window + break; + case APPLICATION_RESOURCE: + // use main window - should not need any window + // UI = application.getUI(); + break; + default: + uI = application.getUIForRequest(wrappedRequest); } + // if window not found, not a problem - use null } finally { application.getLock().unlock(); } @@ -681,14 +676,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants { wrappedResponse, portletWrapper, uI); return; } else { - /* - * Removes the application if it has stopped - */ - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - handleOtherRequest(wrappedRequest, wrappedResponse, requestType, application, applicationContext, applicationManager); @@ -711,6 +698,10 @@ public class VaadinPortlet extends GenericPortlet implements Constants { application.cleanupInactiveUIs(); } + if (applicationRunning) { + application.cleanupInactiveUIs(); + } + if (application != null) { requestTimer.stop(application); } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index afdfdad121..9977fa0da7 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -22,6 +22,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Iterator; import java.util.Locale; import java.util.ServiceLoader; @@ -34,6 +35,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.ui.UI; import com.vaadin.util.CurrentInstance; import com.vaadin.util.ReflectTools; @@ -51,6 +53,10 @@ public abstract class VaadinService implements Serializable { VaadinSessionInitializationListener.class, "vaadinSessionInitialized", VaadinSessionInitializeEvent.class); + private static final Method SESSION_DESTROY_METHOD = ReflectTools + .findMethod(VaadinSessionDestroyListener.class, + "vaadinSessionDestroyed", VaadinSessionDestroyEvent.class); + /** * @deprecated Only supported for {@link LegacyApplication}. */ @@ -254,6 +260,44 @@ public abstract class VaadinService implements Serializable { } /** + * Adds a listener that gets notified when a Vaadin session that has been + * initialized for this service is destroyed. + * + * @see #addVaadinSessionInitializationListener(VaadinSessionInitializationListener) + * + * @param listener + * the vaadin session destroy listener + */ + public void addVaadinSessionDestroyListener( + VaadinSessionDestroyListener listener) { + eventRouter.addListener(VaadinSessionDestroyEvent.class, listener, + SESSION_DESTROY_METHOD); + } + + public void fireSessionDestroy(VaadinSession vaadinSession) { + for (UI ui : new ArrayList<UI>(vaadinSession.getUIs())) { + vaadinSession.cleanupUI(ui); + } + + eventRouter + .fireEvent(new VaadinSessionDestroyEvent(this, vaadinSession)); + } + + /** + * Removes a Vaadin session destroy listener from this service. + * + * @see #addVaadinSessionDestroyListener(VaadinSessionDestroyListener) + * + * @param listener + * the vaadin session destroy listener + */ + public void removeVaadinSessionDestroyListener( + VaadinSessionDestroyListener listener) { + eventRouter.removeListener(VaadinSessionDestroyEvent.class, listener, + SESSION_DESTROY_METHOD); + } + + /** * Attempts to find a Vaadin session associated with this request. * * @param request @@ -324,6 +368,7 @@ public abstract class VaadinService implements Serializable { throw new ServiceException(e); } + session.setVaadinService(this); session.storeInSession(request.getWrappedSession()); URL applicationUrl; @@ -404,7 +449,6 @@ public abstract class VaadinService implements Serializable { return; } - application.close(); if (session != null) { application.removeFromSession(); } @@ -426,11 +470,6 @@ public abstract class VaadinService implements Serializable { return null; } - if (!sessionApplication.isRunning()) { - sessionApplication.removeFromSession(); - return null; - } - return sessionApplication; } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 376750980b..3c129c49a8 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -41,7 +41,6 @@ import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import com.vaadin.DefaultDeploymentConfiguration; import com.vaadin.sass.ScssStylesheet; @@ -481,13 +480,6 @@ public class VaadinServlet extends HttpServlet implements Constants { return; } - // Removes application if it has stopped (maybe by thread or - // transactionlistener) - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - if (applicationManager.handleApplicationRequest(request, response)) { return; } @@ -1348,35 +1340,6 @@ public class VaadinServlet extends HttpServlet implements Constants { } /** - * Ends the application. - * - * @param request - * the HTTP request. - * @param response - * the HTTP response to write to. - * @param application - * the application to end. - * @throws IOException - * if the writing failed due to input/output error. - */ - private void endApplication(HttpServletRequest request, - HttpServletResponse response, VaadinSession application) - throws IOException { - - String logoutUrl = application.getLogoutURL(); - if (logoutUrl == null) { - logoutUrl = application.getURL().toString(); - } - - final HttpSession session = request.getSession(); - if (session != null) { - application.removeFromSession(); - } - - response.sendRedirect(response.encodeRedirectURL(logoutUrl)); - } - - /** * Returns the path info; note that this _can_ be different than * request.getPathInfo(). Examples where this might be useful: * <ul> diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index f1d4ab343a..5acc1e0ca3 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -19,11 +19,11 @@ package com.vaadin.server; import java.io.Serializable; import java.lang.reflect.Method; import java.net.URL; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EventObject; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -37,6 +37,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; +import com.vaadin.LegacyApplication; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.util.converter.ConverterFactory; import com.vaadin.data.util.converter.DefaultConverterFactory; @@ -154,22 +155,11 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { private URL applicationUrl; /** - * Application status. - */ - private volatile boolean applicationIsRunning = false; - - /** * Default locale of the session. */ private Locale locale; /** - * URL where the user is redirected to on application close, or null if - * application is just closed without redirection. - */ - private String logoutURL = null; - - /** * Session wide error handler which is used by default if an error is left * unhandled. */ @@ -206,6 +196,8 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { private final Map<String, Object> attributes = new HashMap<String, Object>(); + private VaadinService vaadinService; + /** * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent) */ @@ -221,7 +213,19 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { public void valueUnbound(HttpSessionBindingEvent event) { // If we are going to be unbound from the session, the session must be // closing - close(); + if (vaadinService != null) { + vaadinService.fireSessionDestroy(this); + } + } + + /** + * Sets the Vaadin service to which this session belongs. + * + * @param vaadinService + * the Vaadin service. + */ + public void setVaadinService(VaadinService vaadinService) { + this.vaadinService = vaadinService; } /** @@ -302,25 +306,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** - * Ends the session. - * <p> - * When the session is closed, close events are fired for its UIs, its state - * is removed from the underlying session, and the browser window is - * redirected to the application logout url set with - * {@link #setLogoutURL(String)}. If the logout url has not been set, the - * browser window is reloaded and the application is restarted. - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - public void close() { - applicationIsRunning = false; - for (UI ui : getUIs()) { - ui.fireCleanupEvent(); - } - } - - /** * @param underlyingSession * @return * @@ -389,25 +374,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { applicationUrl = event.getApplicationUrl(); configuration = event.getConfiguration(); communicationManager = event.getCommunicationManager(); - applicationIsRunning = true; - } - - /** - * Tests if the application is running or if it has been finished. - * - * <p> - * Application starts running when its {@link #start(SessionStartEvent)} - * method has been called and stops when the {@link #close()} is called. - * </p> - * - * @return <code>true</code> if the application is running, - * <code>false</code> if not. - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - public boolean isRunning() { - return applicationIsRunning; } /** @@ -567,41 +533,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** - * Returns the URL user is redirected to on application close. If the URL is - * <code>null</code>, the application is closed normally as defined by the - * application running environment. - * <p> - * Desktop application just closes the application window and - * web-application redirects the browser to application main URL. - * </p> - * - * @return the URL. - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - public String getLogoutURL() { - return logoutURL; - } - - /** - * Sets the URL user is redirected to on application close. If the URL is - * <code>null</code>, the application is closed normally as defined by the - * application running environment: Desktop application just closes the - * application window and web-application redirects the browser to - * application main URL. - * - * @param logoutURL - * the logoutURL to set. - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - public void setLogoutURL(String logoutURL) { - this.logoutURL = logoutURL; - } - - /** * Gets the session's error handler. * * @return the current error handler @@ -1180,12 +1111,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { */ @Deprecated public void cleanupInactiveUIs() { - for (Iterator<UI> i = uIs.values().iterator(); i.hasNext();) { - UI ui = i.next(); + for (UI ui : new ArrayList<UI>(uIs.values())) { if (!isUIAlive(ui)) { - i.remove(); - retainOnRefreshUIs.values().remove(ui.getUIId()); - ui.fireCleanupEvent(); + cleanupUI(ui); getLogger().fine( "Closed UI #" + ui.getUIId() + " due to inactivity"); } @@ -1193,6 +1121,25 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** + * Called by the framework to remove an UI instance because it has been + * inactive. + * + * @param ui + * the UI to remove + * + * @deprecated Method is declared as public only to support + * {@link LegacyApplication#close()} and will be removed when + * LegacyApplciation support is removed. + */ + @Deprecated + public void cleanupUI(UI ui) { + Integer id = Integer.valueOf(ui.getUIId()); + uIs.remove(id); + retainOnRefreshUIs.values().remove(id); + ui.fireCleanupEvent(); + } + + /** * Returns the number of seconds that must pass without a valid heartbeat or * UIDL request being received from a UI before that UI is removed from the * application. This is a lower bound; it might take longer to close an diff --git a/server/src/com/vaadin/server/VaadinSessionDestroyEvent.java b/server/src/com/vaadin/server/VaadinSessionDestroyEvent.java new file mode 100644 index 0000000000..3916f756e9 --- /dev/null +++ b/server/src/com/vaadin/server/VaadinSessionDestroyEvent.java @@ -0,0 +1,70 @@ +/* + * 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.server; + +import java.util.EventObject; + +/** + * Event fired when a Vaadin session is no longer in use. + * + * @see VaadinSessionDestroyListener#vaadinSessionDestroyed(VaadinSessionDestroyEvent) + * + * @author Vaadin Ltd + * @since 7.0.0 + */ +public class VaadinSessionDestroyEvent extends EventObject { + + private final VaadinSession session; + + /** + * Creates a new event. + * + * @param service + * the Vaadin service from which the even originates + * @param session + * the Vaadin session that is no longer used + */ + public VaadinSessionDestroyEvent(VaadinService service, + VaadinSession session) { + super(service); + this.session = session; + } + + @Override + public VaadinService getSource() { + return (VaadinService) super.getSource(); + } + + /** + * Gets the Vaadin service from which the even originates. + * + * @return the Vaadin service + */ + public VaadinService getVaadinService() { + return getSource(); + } + + /** + * Gets the Vaadin session that is no longer used. + * + * @return the Vaadin session + */ + public VaadinSession getVaadinSession() { + return session; + } + +} diff --git a/server/src/com/vaadin/server/VaadinSessionDestroyListener.java b/server/src/com/vaadin/server/VaadinSessionDestroyListener.java new file mode 100644 index 0000000000..3f516c1eda --- /dev/null +++ b/server/src/com/vaadin/server/VaadinSessionDestroyListener.java @@ -0,0 +1,35 @@ +/* + * 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.server; + +/** + * A listener that gets notified when a Vaadin session is no longer used. + * + * @see VaadinService#addVaadinSessionDestroyListener(VaadinSessionDestroyListener) + * + * @author Vaadin Ltd + * @since 7.0.0 + */ +public interface VaadinSessionDestroyListener { + /** + * Called when a Vaadin session is no longer used. + * + * @param event + * the event with details about the destroyed session + */ + public void vaadinSessionDestroyed(VaadinSessionDestroyEvent event); +} |