summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-09-20 13:52:22 +0300
committerLeif Åstrand <leif@vaadin.com>2012-09-20 13:52:37 +0300
commit6b28dc7bf41b8590fcab3d60afd5aa407f1f1401 (patch)
tree9f11e412e2dce3d6b495d29a9c954a70603aa036 /server
parentd66d9b3f5d3a85fb8016eb75ae68267d50244cd9 (diff)
downloadvaadin-framework-6b28dc7bf41b8590fcab3d60afd5aa407f1f1401.tar.gz
vaadin-framework-6b28dc7bf41b8590fcab3d60afd5aa407f1f1401.zip
Refactor how LegacyApplication and VaadinSession are "closed" (#9635)
Diffstat (limited to 'server')
-rw-r--r--server/src/com/vaadin/LegacyApplication.java150
-rw-r--r--server/src/com/vaadin/server/AbstractCommunicationManager.java74
-rw-r--r--server/src/com/vaadin/server/LegacyApplicationUIProvider.java134
-rw-r--r--server/src/com/vaadin/server/LegacyVaadinPortlet.java35
-rw-r--r--server/src/com/vaadin/server/LegacyVaadinServlet.java38
-rw-r--r--server/src/com/vaadin/server/VaadinPortlet.java61
-rw-r--r--server/src/com/vaadin/server/VaadinService.java51
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java37
-rw-r--r--server/src/com/vaadin/server/VaadinSession.java129
-rw-r--r--server/src/com/vaadin/server/VaadinSessionDestroyEvent.java70
-rw-r--r--server/src/com/vaadin/server/VaadinSessionDestroyListener.java35
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);
+}