summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Ahlroos <john@vaadin.com>2012-09-24 11:42:58 +0300
committerJohn Ahlroos <john@vaadin.com>2012-09-24 11:42:58 +0300
commitf9df64d3e490d0fa28d6f8fe31b0237009535804 (patch)
tree7814dfad8eadc527f36af61ce06587186da500ca
parentbd576ade92607669fa7806fed18e90789027a80d (diff)
parente223589aae4ee77043ba156961a663b73ad3d8cb (diff)
downloadvaadin-framework-f9df64d3e490d0fa28d6f8fe31b0237009535804.tar.gz
vaadin-framework-f9df64d3e490d0fa28d6f8fe31b0237009535804.zip
Merge branch 'master' into html5-doctype
-rw-r--r--server/src/com/vaadin/LegacyApplication.java150
-rw-r--r--server/src/com/vaadin/navigator/Navigator.java90
-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.java38
-rw-r--r--server/src/com/vaadin/server/LegacyVaadinServlet.java41
-rw-r--r--server/src/com/vaadin/server/ServiceException.java8
-rw-r--r--server/src/com/vaadin/server/ServletPortletHelper.java40
-rw-r--r--server/src/com/vaadin/server/VaadinPortlet.java285
-rw-r--r--server/src/com/vaadin/server/VaadinService.java74
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java53
-rw-r--r--server/src/com/vaadin/server/VaadinServletSession.java5
-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
-rw-r--r--server/src/com/vaadin/ui/UI.java10
-rw-r--r--uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java2
-rw-r--r--uitest/src/com/vaadin/tests/TestForUpload.java4
-rw-r--r--uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java4
-rw-r--r--uitest/src/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java2
-rw-r--r--uitest/src/com/vaadin/tests/navigator/NavigatorTest.html55
-rw-r--r--uitest/src/com/vaadin/tests/navigator/NavigatorTest.java11
22 files changed, 797 insertions, 517 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/navigator/Navigator.java b/server/src/com/vaadin/navigator/Navigator.java
index 257dfa208f..c9f6946ce5 100644
--- a/server/src/com/vaadin/navigator/Navigator.java
+++ b/server/src/com/vaadin/navigator/Navigator.java
@@ -112,7 +112,7 @@ public class Navigator implements Serializable {
public String getState() {
String fragment = page.getFragment();
if (fragment.startsWith("!")) {
- return page.getFragment().substring(1);
+ return fragment.substring(1);
} else {
return "";
}
@@ -338,6 +338,7 @@ public class Navigator implements Serializable {
private View currentView = null;
private List<ViewChangeListener> listeners = new LinkedList<ViewChangeListener>();
private List<ViewProvider> providers = new LinkedList<ViewProvider>();
+ private ViewProvider errorProvider;
/**
* Creates a navigator that is tracking the active view using URI fragments
@@ -443,6 +444,8 @@ public class Navigator implements Serializable {
*
* @param navigationState
* view name and parameters
+ *
+ * @throws IllegalArgumentException
*/
public void navigateTo(String navigationState) {
String longestViewName = null;
@@ -459,6 +462,10 @@ public class Navigator implements Serializable {
}
}
}
+ if (viewWithLongestName == null && errorProvider != null) {
+ longestViewName = errorProvider.getViewName(navigationState);
+ viewWithLongestName = errorProvider.getView(longestViewName);
+ }
if (viewWithLongestName != null) {
String parameters = "";
if (navigationState.length() > longestViewName.length() + 1) {
@@ -466,8 +473,12 @@ public class Navigator implements Serializable {
.substring(longestViewName.length() + 1);
}
navigateTo(viewWithLongestName, longestViewName, parameters);
+ } else {
+ throw new IllegalArgumentException(
+ "Trying to navigate to an unknown state '"
+ + navigationState
+ + "' and an error view provider not present");
}
- // TODO if no view is found, what to do?
}
/**
@@ -600,11 +611,11 @@ public class Navigator implements Serializable {
}
/**
- * Register a view class for a view name.
+ * Registers a view class for a view name.
* <p>
* Registering another view with a name that is already registered
* overwrites the old registration of the same type.
- *
+ * <p>
* A new view instance is created every time a view is requested.
*
* @param viewName
@@ -676,9 +687,76 @@ public class Navigator implements Serializable {
}
/**
- * Adds a listener for listening to changes of the active view.
+ * Registers a view class that is instantiated when no other view matches
+ * the navigation state. This implicitly sets an appropriate error view
+ * provider and overrides any previous
+ * {@link #setErrorProvider(ViewProvider)} call.
+ *
+ * @param viewClass
+ * The View class whose instance should be used as the error
+ * view.
+ */
+ public void setErrorView(final Class<? extends View> viewClass) {
+ setErrorProvider(new ViewProvider() {
+ @Override
+ public View getView(String viewName) {
+ try {
+ return viewClass.newInstance();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String getViewName(String navigationState) {
+ return navigationState;
+ }
+ });
+ }
+
+ /**
+ * Registers a view that is displayed when no other view matches the
+ * navigation state. This implicitly sets an appropriate error view provider
+ * and overrides any previous {@link #setErrorProvider(ViewProvider)} call.
+ *
+ * @param view
+ * The View that should be used as the error view.
+ */
+ public void setErrorView(final View view) {
+ setErrorProvider(new ViewProvider() {
+ @Override
+ public View getView(String viewName) {
+ return view;
+ };
+
+ @Override
+ public String getViewName(String navigationState) {
+ return navigationState;
+ }
+ });
+ }
+
+ /**
+ * Registers a view provider that is queried for a view when no other view
+ * matches the navigation state. An error view provider should match any
+ * navigation state, but could return different views for different states.
+ * Its <code>getViewName(String navigationState)</code> should return
+ * <code>navigationState</code>.
+ *
+ * @param provider
+ */
+ public void setErrorProvider(ViewProvider provider) {
+ errorProvider = provider;
+ }
+
+ /**
+ * Listen to changes of the active view.
* <p>
- * The listener will get notified after the view has changed.
+ * Registered listeners are invoked in registration order before (
+ * {@link ViewChangeListener#beforeViewChange(ViewChangeEvent)
+ * beforeViewChange()}) and after (
+ * {@link ViewChangeListener#afterViewChange(ViewChangeEvent)
+ * afterViewChange()}) a view change occurs.
*
* @param listener
* Listener to invoke during a view change.
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..6aa8fb7165 100644
--- a/server/src/com/vaadin/server/LegacyVaadinPortlet.java
+++ b/server/src/com/vaadin/server/LegacyVaadinPortlet.java
@@ -20,10 +20,29 @@ import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import com.vaadin.LegacyApplication;
-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();
@@ -51,7 +70,7 @@ public class LegacyVaadinPortlet extends VaadinPortlet {
try {
return ServletPortletHelper
.getLegacyApplicationClass(getVaadinService());
- } catch (ApplicationClassException e) {
+ } catch (ServiceException e) {
throw new RuntimeException(e);
}
}
@@ -68,21 +87,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..ace29e9e1f 100644
--- a/server/src/com/vaadin/server/LegacyVaadinServlet.java
+++ b/server/src/com/vaadin/server/LegacyVaadinServlet.java
@@ -21,10 +21,30 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import com.vaadin.LegacyApplication;
-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);
@@ -50,7 +70,7 @@ public class LegacyVaadinServlet extends VaadinServlet {
try {
return ServletPortletHelper
.getLegacyApplicationClass(getVaadinService());
- } catch (ApplicationClassException e) {
+ } catch (ServiceException e) {
throw new RuntimeException(e);
}
}
@@ -65,27 +85,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/ServiceException.java b/server/src/com/vaadin/server/ServiceException.java
index 538e8b30ea..ac693e5747 100644
--- a/server/src/com/vaadin/server/ServiceException.java
+++ b/server/src/com/vaadin/server/ServiceException.java
@@ -18,12 +18,16 @@ package com.vaadin.server;
public class ServiceException extends Exception {
- public ServiceException(Exception e) {
- super(e);
+ public ServiceException(Throwable t) {
+ super(t);
}
public ServiceException(String message) {
super(message);
}
+ public ServiceException(String message, Throwable t) {
+ super(message, t);
+ }
+
}
diff --git a/server/src/com/vaadin/server/ServletPortletHelper.java b/server/src/com/vaadin/server/ServletPortletHelper.java
index 7f4a05deef..3f2674392c 100644
--- a/server/src/com/vaadin/server/ServletPortletHelper.java
+++ b/server/src/com/vaadin/server/ServletPortletHelper.java
@@ -30,26 +30,15 @@ class ServletPortletHelper implements Serializable {
*/
static final SystemMessages DEFAULT_SYSTEM_MESSAGES = new SystemMessages();
- public static class ApplicationClassException extends Exception {
-
- public ApplicationClassException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public ApplicationClassException(String message) {
- super(message);
- }
- }
-
static Class<? extends LegacyApplication> getLegacyApplicationClass(
- VaadinService vaadinService) throws ApplicationClassException {
+ VaadinService vaadinService) throws ServiceException {
Properties initParameters = vaadinService.getDeploymentConfiguration()
.getInitParameters();
String applicationParameter = initParameters.getProperty("application");
ClassLoader classLoader = vaadinService.getClassLoader();
if (applicationParameter == null) {
- throw new ApplicationClassException(
+ throw new ServiceException(
"No \"application\" init parameter found");
}
@@ -57,16 +46,15 @@ class ServletPortletHelper implements Serializable {
return classLoader.loadClass(applicationParameter).asSubclass(
LegacyApplication.class);
} catch (final ClassNotFoundException e) {
- throw new ApplicationClassException(
- "Failed to load application class: " + applicationParameter,
- e);
+ throw new ServiceException("Failed to load application class: "
+ + applicationParameter, e);
}
}
private static void verifyUIClass(String className, ClassLoader classLoader)
- throws ApplicationClassException {
+ throws ServiceException {
if (className == null) {
- throw new ApplicationClassException(VaadinSession.UI_PARAMETER
+ throw new ServiceException(VaadinSession.UI_PARAMETER
+ " init parameter not defined");
}
@@ -74,19 +62,17 @@ class ServletPortletHelper implements Serializable {
try {
Class<?> uiClass = classLoader.loadClass(className);
if (!UI.class.isAssignableFrom(uiClass)) {
- throw new ApplicationClassException(className
- + " does not implement UI");
+ throw new ServiceException(className + " does not implement UI");
}
// Try finding a default constructor, else throw exception
uiClass.getConstructor();
} catch (ClassNotFoundException e) {
- throw new ApplicationClassException(className
- + " could not be loaded", e);
+ throw new ServiceException(className + " could not be loaded", e);
} catch (SecurityException e) {
- throw new ApplicationClassException("Could not access " + className
+ throw new ServiceException("Could not access " + className
+ " class", e);
} catch (NoSuchMethodException e) {
- throw new ApplicationClassException(className
+ throw new ServiceException(className
+ " doesn't have a public no-args constructor");
}
}
@@ -132,7 +118,7 @@ class ServletPortletHelper implements Serializable {
}
public static void initDefaultUIProvider(VaadinSession application,
- VaadinService vaadinService) throws ApplicationClassException {
+ VaadinService vaadinService) throws ServiceException {
String uiProperty = vaadinService.getDeploymentConfiguration()
.getInitParameters().getProperty(VaadinSession.UI_PARAMETER);
if (uiProperty != null) {
@@ -142,9 +128,9 @@ class ServletPortletHelper implements Serializable {
}
public static void checkUiProviders(VaadinSession newApplication)
- throws ApplicationClassException {
+ throws ServiceException {
if (newApplication.getUIProviders().isEmpty()) {
- throw new ApplicationClassException(
+ throw new ServiceException(
"No UIProvider has been added to the application and there is no \""
+ VaadinSession.UI_PARAMETER + "\" init parameter.");
}
diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java
index dc1f93b2a8..074c2aa9cc 100644
--- a/server/src/com/vaadin/server/VaadinPortlet.java
+++ b/server/src/com/vaadin/server/VaadinPortlet.java
@@ -222,10 +222,16 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
return new PortletCommunicationManager(session);
}
- public static WrappedPortletRequest getCurrentRequest() {
+ public static PortletRequest getCurrentPortletRequest() {
WrappedRequest currentRequest = VaadinService.getCurrentRequest();
try {
- return WrappedPortletRequest.cast(currentRequest);
+ WrappedPortletRequest request = WrappedPortletRequest
+ .cast(currentRequest);
+ if (request != null) {
+ return request.getPortletRequest();
+ } else {
+ return null;
+ }
} catch (ClassCastException e) {
return null;
}
@@ -235,6 +241,11 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
return (WrappedPortletResponse) VaadinService.getCurrentResponse();
}
+ @Override
+ protected VaadinSession createVaadinSession(WrappedRequest request)
+ throws ServiceException {
+ return new VaadinPortletSession();
+ }
}
public static class WrappedHttpAndPortletRequest extends
@@ -520,84 +531,87 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
CurrentInstance.clearAll();
setCurrent(this);
- AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper(
- this);
-
- WrappedPortletRequest wrappedRequest = createWrappedRequest(request);
-
- WrappedPortletResponse wrappedResponse = new WrappedPortletResponse(
- response, getVaadinService());
-
- getVaadinService().setCurrentInstances(wrappedRequest, wrappedResponse);
-
- RequestType requestType = getRequestType(wrappedRequest);
-
- if (requestType == RequestType.UNKNOWN) {
- handleUnknownRequest(request, response);
- } else if (requestType == RequestType.DUMMY) {
- /*
- * This dummy page is used by action responses to redirect to, in
- * order to prevent the boot strap code from being rendered into
- * strange places such as iframes.
- */
- ((ResourceResponse) response).setContentType("text/html");
- final OutputStream out = ((ResourceResponse) response)
- .getPortletOutputStream();
- final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
- new OutputStreamWriter(out, "UTF-8")));
- outWriter.print("<html><body>dummy page</body></html>");
- outWriter.close();
- } else if (requestType == RequestType.STATIC_FILE) {
- serveStaticResources((ResourceRequest) request,
- (ResourceResponse) response);
- } else {
- VaadinSession application = null;
- boolean applicationRunning = false;
+ try {
+ AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper(
+ this);
- try {
- // TODO What about PARAM_UNLOADBURST & redirectToApplication??
+ WrappedPortletRequest wrappedRequest = createWrappedRequest(request);
- /* Find out which application this request is related to */
- application = getVaadinService().findVaadinSession(
- wrappedRequest);
- if (application == null) {
- return;
- }
- VaadinSession.setCurrent(application);
- request.setAttribute(VaadinSession.class.getName(), application);
+ WrappedPortletResponse wrappedResponse = new WrappedPortletResponse(
+ response, getVaadinService());
+
+ getVaadinService().setCurrentInstances(wrappedRequest,
+ wrappedResponse);
+ RequestType requestType = getRequestType(wrappedRequest);
+
+ if (requestType == RequestType.UNKNOWN) {
+ handleUnknownRequest(request, response);
+ } else if (requestType == RequestType.DUMMY) {
/*
- * Get or create an application context and an application
- * manager for the session
+ * This dummy page is used by action responses to redirect to,
+ * in order to prevent the boot strap code from being rendered
+ * into strange places such as iframes.
*/
- VaadinPortletSession applicationContext = (VaadinPortletSession) application;
-
- PortletCommunicationManager applicationManager = (PortletCommunicationManager) applicationContext
- .getApplicationManager();
-
- if (requestType == RequestType.CONNECTOR_RESOURCE) {
- applicationManager.serveConnectorResource(wrappedRequest,
- wrappedResponse);
- return;
- } else if (requestType == RequestType.HEARTBEAT) {
- applicationManager.handleHeartbeatRequest(wrappedRequest,
- wrappedResponse, application);
- return;
- }
+ ((ResourceResponse) response).setContentType("text/html");
+ final OutputStream out = ((ResourceResponse) response)
+ .getPortletOutputStream();
+ final PrintWriter outWriter = new PrintWriter(
+ new BufferedWriter(new OutputStreamWriter(out, "UTF-8")));
+ outWriter.print("<html><body>dummy page</body></html>");
+ outWriter.close();
+ } else if (requestType == RequestType.STATIC_FILE) {
+ serveStaticResources((ResourceRequest) request,
+ (ResourceResponse) response);
+ } else {
+ VaadinSession application = null;
+ boolean applicationRunning = false;
+
+ try {
+ // TODO What about PARAM_UNLOADBURST &
+ // redirectToApplication??
- /* Update browser information from request */
- applicationContext.getBrowser().updateRequestDetails(
- wrappedRequest);
+ /* Find out which application this request is related to */
+ application = getVaadinService().findVaadinSession(
+ wrappedRequest);
+ if (application == null) {
+ return;
+ }
+ VaadinSession.setCurrent(application);
+ request.setAttribute(VaadinSession.class.getName(),
+ application);
- applicationRunning = true;
+ /*
+ * Get or create an application context and an application
+ * manager for the session
+ */
+ VaadinPortletSession applicationContext = (VaadinPortletSession) application;
- /* Notify listeners */
+ PortletCommunicationManager applicationManager = (PortletCommunicationManager) applicationContext
+ .getApplicationManager();
- // Finds the window within the application
- UI uI = null;
- application.getLock().lock();
- try {
- if (application.isRunning()) {
+ if (requestType == RequestType.CONNECTOR_RESOURCE) {
+ applicationManager.serveConnectorResource(
+ wrappedRequest, wrappedResponse);
+ return;
+ } else if (requestType == RequestType.HEARTBEAT) {
+ applicationManager.handleHeartbeatRequest(
+ wrappedRequest, wrappedResponse, application);
+ return;
+ }
+
+ /* Update browser information from request */
+ applicationContext.getBrowser().updateRequestDetails(
+ wrappedRequest);
+
+ applicationRunning = true;
+
+ /* Notify listeners */
+
+ // Finds the window within the application
+ UI uI = null;
+ application.getLock().lock();
+ try {
switch (requestType) {
case RENDER:
case ACTION:
@@ -621,81 +635,80 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
uI = application.getUIForRequest(wrappedRequest);
}
// if window not found, not a problem - use null
+ } finally {
+ application.getLock().unlock();
}
- } finally {
- application.getLock().unlock();
- }
- // TODO Should this happen before or after the transaction
- // starts?
- if (request instanceof RenderRequest) {
- applicationContext.firePortletRenderRequest(uI,
- (RenderRequest) request, (RenderResponse) response);
- } else if (request instanceof ActionRequest) {
- applicationContext.firePortletActionRequest(uI,
- (ActionRequest) request, (ActionResponse) response);
- } else if (request instanceof EventRequest) {
- applicationContext.firePortletEventRequest(uI,
- (EventRequest) request, (EventResponse) response);
- } else if (request instanceof ResourceRequest) {
- applicationContext.firePortletResourceRequest(uI,
- (ResourceRequest) request,
- (ResourceResponse) response);
- }
+ // TODO Should this happen before or after the transaction
+ // starts?
+ if (request instanceof RenderRequest) {
+ applicationContext.firePortletRenderRequest(uI,
+ (RenderRequest) request,
+ (RenderResponse) response);
+ } else if (request instanceof ActionRequest) {
+ applicationContext.firePortletActionRequest(uI,
+ (ActionRequest) request,
+ (ActionResponse) response);
+ } else if (request instanceof EventRequest) {
+ applicationContext.firePortletEventRequest(uI,
+ (EventRequest) request,
+ (EventResponse) response);
+ } else if (request instanceof ResourceRequest) {
+ applicationContext.firePortletResourceRequest(uI,
+ (ResourceRequest) request,
+ (ResourceResponse) response);
+ }
- /* Handle the request */
- if (requestType == RequestType.FILE_UPLOAD) {
- // UI is resolved in handleFileUpload by
- // PortletCommunicationManager
- applicationManager.handleFileUpload(application,
- wrappedRequest, wrappedResponse);
- return;
- } else if (requestType == RequestType.BROWSER_DETAILS) {
- applicationManager.handleBrowserDetailsRequest(
- wrappedRequest, wrappedResponse, application);
- return;
- } else if (requestType == RequestType.UIDL) {
- // Handles AJAX UIDL requests
- applicationManager.handleUidlRequest(wrappedRequest,
- wrappedResponse, portletWrapper, uI);
- return;
- } else {
- /*
- * Removes the application if it has stopped
- */
- if (!application.isRunning()) {
- endApplication(request, response, application);
+ /* Handle the request */
+ if (requestType == RequestType.FILE_UPLOAD) {
+ // UI is resolved in handleFileUpload by
+ // PortletCommunicationManager
+ applicationManager.handleFileUpload(application,
+ wrappedRequest, wrappedResponse);
+ return;
+ } else if (requestType == RequestType.BROWSER_DETAILS) {
+ applicationManager.handleBrowserDetailsRequest(
+ wrappedRequest, wrappedResponse, application);
+ return;
+ } else if (requestType == RequestType.UIDL) {
+ // Handles AJAX UIDL requests
+ applicationManager.handleUidlRequest(wrappedRequest,
+ wrappedResponse, portletWrapper, uI);
return;
+ } else {
+ handleOtherRequest(wrappedRequest, wrappedResponse,
+ requestType, application, applicationContext,
+ applicationManager);
}
+ } catch (final SessionExpiredException e) {
+ // TODO Figure out a better way to deal with
+ // SessionExpiredExceptions
+ getLogger().finest("A user session has expired");
+ } catch (final GeneralSecurityException e) {
+ // TODO Figure out a better way to deal with
+ // GeneralSecurityExceptions
+ getLogger()
+ .fine("General security exception, the security key was probably incorrect.");
+ } catch (final Throwable e) {
+ handleServiceException(wrappedRequest, wrappedResponse,
+ application, e);
+ } finally {
- handleOtherRequest(wrappedRequest, wrappedResponse,
- requestType, application, applicationContext,
- applicationManager);
- }
- } catch (final SessionExpiredException e) {
- // TODO Figure out a better way to deal with
- // SessionExpiredExceptions
- getLogger().finest("A user session has expired");
- } catch (final GeneralSecurityException e) {
- // TODO Figure out a better way to deal with
- // GeneralSecurityExceptions
- getLogger()
- .fine("General security exception, the security key was probably incorrect.");
- } catch (final Throwable e) {
- handleServiceException(wrappedRequest, wrappedResponse,
- application, e);
- } finally {
-
- if (applicationRunning) {
- application.cleanupInactiveUIs();
- }
+ if (applicationRunning) {
+ application.cleanupInactiveUIs();
+ }
- CurrentInstance.clearAll();
+ if (applicationRunning) {
+ application.cleanupInactiveUIs();
+ }
- if (application != null) {
- requestTimer.stop(application);
+ if (application != null) {
+ requestTimer.stop(application);
+ }
}
}
+ } finally {
+ CurrentInstance.clearAll();
}
}
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index 80590df4a0..eb5d838b72 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;
@@ -32,8 +33,8 @@ import javax.servlet.ServletException;
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 +52,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 +259,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
@@ -318,6 +361,9 @@ public abstract class VaadinService implements Serializable {
throws ServiceException {
VaadinSession session = createVaadinSession(request);
+ ServletPortletHelper.initDefaultUIProvider(session, this);
+
+ session.setVaadinService(this);
session.storeInSession(request.getWrappedSession());
URL applicationUrl;
@@ -376,18 +422,8 @@ public abstract class VaadinService implements Serializable {
* @throws ServletException
* @throws MalformedURLException
*/
- private VaadinServletSession createVaadinSession(WrappedRequest request)
- throws ServiceException {
- VaadinServletSession session = new VaadinServletSession();
-
- try {
- ServletPortletHelper.initDefaultUIProvider(session, this);
- } catch (ApplicationClassException e) {
- throw new ServiceException(e);
- }
-
- return session;
- }
+ protected abstract VaadinSession createVaadinSession(WrappedRequest request)
+ throws ServiceException;
private void onVaadinSessionStarted(WrappedRequest request,
VaadinSession session) throws ServiceException {
@@ -395,11 +431,7 @@ public abstract class VaadinService implements Serializable {
eventRouter.fireEvent(new VaadinSessionInitializeEvent(this, session,
request));
- try {
- ServletPortletHelper.checkUiProviders(session);
- } catch (ApplicationClassException e) {
- throw new ServiceException(e);
- }
+ ServletPortletHelper.checkUiProviders(session);
}
private void closeApplication(VaadinSession application,
@@ -408,7 +440,6 @@ public abstract class VaadinService implements Serializable {
return;
}
- application.close();
if (session != null) {
application.removeFromSession();
}
@@ -430,11 +461,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 c42d029dc4..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;
@@ -198,10 +197,16 @@ public class VaadinServlet extends HttpServlet implements Constants {
return new CommunicationManager(session);
}
- public static WrappedHttpServletRequest getCurrentRequest() {
+ public static HttpServletRequest getCurrentServletRequest() {
WrappedRequest currentRequest = VaadinService.getCurrentRequest();
try {
- return WrappedHttpServletRequest.cast(currentRequest);
+ WrappedHttpServletRequest request = WrappedHttpServletRequest
+ .cast(currentRequest);
+ if (request != null) {
+ return request.getHttpServletRequest();
+ } else {
+ return null;
+ }
} catch (ClassCastException e) {
return null;
}
@@ -211,6 +216,12 @@ public class VaadinServlet extends HttpServlet implements Constants {
return (WrappedHttpServletResponse) VaadinService
.getCurrentResponse();
}
+
+ @Override
+ protected VaadinSession createVaadinSession(WrappedRequest request)
+ throws ServiceException {
+ return new VaadinServletSession();
+ }
}
private static class AbstractApplicationServletWrapper implements Callback {
@@ -469,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;
}
@@ -1336,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/VaadinServletSession.java b/server/src/com/vaadin/server/VaadinServletSession.java
index b2dc84d857..9a937b401b 100644
--- a/server/src/com/vaadin/server/VaadinServletSession.java
+++ b/server/src/com/vaadin/server/VaadinServletSession.java
@@ -19,6 +19,7 @@ package com.vaadin.server;
import java.util.Enumeration;
import java.util.HashMap;
+import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
@@ -58,8 +59,8 @@ public class VaadinServletSession extends VaadinSession {
* to avoid session fixation attacks.
*/
public void reinitializeSession() {
- WrappedHttpServletRequest currentRequest = ServletService
- .getCurrentRequest();
+ HttpServletRequest currentRequest = ServletService
+ .getCurrentServletRequest();
if (currentRequest == null) {
throw new IllegalStateException(
"Can not reinitialize session outside normal request handling.");
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);
+}
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index b15a83cdce..0d83f8258d 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -1123,11 +1123,11 @@ public abstract class UI extends AbstractComponentContainer implements
}
/**
- * Adds a close listener to the UI. Close listeners are invoked when the UI
- * is removed from the session due to UI or session expiration.
+ * Adds a cleanup listener to the UI. Cleanup listeners are invoked when the
+ * UI is removed from the session due to UI or session expiration.
*
* @param listener
- * The CloseListener that should be added.
+ * The CleanupListener that should be added.
*/
public void addCleanupListener(CleanupListener listener) {
addListener(CleanupEvent.CLEANUP_EVENT_IDENTIFIER, CleanupEvent.class,
@@ -1156,11 +1156,11 @@ public abstract class UI extends AbstractComponentContainer implements
}
/**
- * Removes a close listener from the UI, if previously added with
+ * Removes a cleanup listener from the UI, if previously added with
* {@link #addCleanupListener(CleanupListener)}.
*
* @param listener
- * The CloseListener that should be removed
+ * The CleanupListener that should be removed
*/
public void removeCleanupListener(CleanupListener listener) {
removeListener(CleanupEvent.CLEANUP_EVENT_IDENTIFIER,
diff --git a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java
index f31b17333a..c27e92626a 100644
--- a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java
+++ b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java
@@ -129,7 +129,7 @@ public class ApplicationRunnerServlet extends LegacyVaadinServlet {
}
@Override
- protected boolean shouldCreateApplication(WrappedHttpServletRequest request)
+ protected boolean shouldCreateApplication(HttpServletRequest request)
throws ServletException {
try {
return LegacyApplication.class.isAssignableFrom(getClassToRun());
diff --git a/uitest/src/com/vaadin/tests/TestForUpload.java b/uitest/src/com/vaadin/tests/TestForUpload.java
index 7146b1a4ff..31298aa392 100644
--- a/uitest/src/com/vaadin/tests/TestForUpload.java
+++ b/uitest/src/com/vaadin/tests/TestForUpload.java
@@ -43,6 +43,7 @@ import com.vaadin.ui.Panel;
import com.vaadin.ui.ProgressIndicator;
import com.vaadin.ui.Select;
import com.vaadin.ui.TextField;
+import com.vaadin.ui.UI.LegacyWindow;
import com.vaadin.ui.Upload;
import com.vaadin.ui.Upload.FinishedEvent;
import com.vaadin.ui.Upload.StartedEvent;
@@ -244,7 +245,8 @@ public class TestForUpload extends CustomComponent implements
@Override
public void buttonClick(ClickEvent event) {
- getSession().close();
+ LegacyWindow window = (LegacyWindow) event.getButton().getUI();
+ window.getApplication().close();
}
});
main.addComponent(restart);
diff --git a/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java b/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java
index e4f8552af1..151b58ed67 100644
--- a/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java
+++ b/uitest/src/com/vaadin/tests/application/ApplicationCloseTest.java
@@ -5,6 +5,7 @@ import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
+import com.vaadin.ui.UI.LegacyWindow;
public class ApplicationCloseTest extends TestBase {
@@ -26,7 +27,8 @@ public class ApplicationCloseTest extends TestBase {
@Override
public void buttonClick(ClickEvent event) {
- event.getButton().getUI().getSession().close();
+ LegacyWindow ui = (LegacyWindow) event.getButton().getUI();
+ ui.getApplication().close();
}
});
diff --git a/uitest/src/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java b/uitest/src/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java
index fecac38697..3a22a46e68 100644
--- a/uitest/src/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java
+++ b/uitest/src/com/vaadin/tests/layouts/ComplexGLColumnExpansionWithColSpan.java
@@ -73,7 +73,7 @@ public class ComplexGLColumnExpansionWithColSpan extends AbstractTestCase {
restart.addListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
- mainLayout.getUI().getSession().close();
+ close();
}
});
diff --git a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html
index 8c4e8f657b..030b30f37a 100644
--- a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html
+++ b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.html
@@ -17,6 +17,11 @@
<td></td>
</tr>
<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
+ <td>1. Navigated to DefaultView with params</td>
+</tr>
+<tr>
<td>click</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
<td></td>
@@ -24,7 +29,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>1. Navigated to ListView with params</td>
+ <td>2. Navigated to ListView with params</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -39,7 +44,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>2. Navigated to EditView with params</td>
+ <td>3. Navigated to EditView with params</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -64,7 +69,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>3. Navigated to ListView with params param=value</td>
+ <td>4. Navigated to ListView with params param=value</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -79,7 +84,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>4. Navigated to EditView with params param=value</td>
+ <td>5. Navigated to EditView with params param=value</td>
</tr>
<tr>
<td>assertLocation</td>
@@ -94,13 +99,53 @@
<tr>
<td>assertText</td>
<td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
- <td>5. Prevent navigation to ForbiddenView</td>
+ <td>6. Prevent navigation to ForbiddenView</td>
</tr>
<tr>
<td>assertLocation</td>
<td>*#!edit/param=value</td>
<td></td>
</tr>
+<tr>
+ <td>runScript</td>
+ <td>window.location.hash='!foo'</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>1000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
+ <td>7. View 'foo' not found!</td>
+</tr>
+<tr>
+ <td>assertLocation</td>
+ <td>*#!foo</td>
+ <td></td>
+</tr>
+<tr>
+ <td>runScript</td>
+ <td>window.location.hash='foo'</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>1000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsnavigatorNavigatorTest::/VVerticalLayout[0]/VOrderedLayout$Slot[4]/VVerticalLayout[0]/VOrderedLayout$Slot[0]/VLabel[0]</td>
+ <td>8. Navigated to DefaultView with params</td>
+</tr>
+<tr>
+ <td>assertLocation</td>
+ <td>*#foo</td>
+ <td></td>
+</tr>
</tbody></table>
</body>
diff --git a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java
index 4986bd21e6..a3f7ce9f5b 100644
--- a/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java
+++ b/uitest/src/com/vaadin/tests/navigator/NavigatorTest.java
@@ -74,6 +74,15 @@ public class NavigatorTest extends UI {
}
}
+ class ErrorView extends Label implements View {
+ @Override
+ public void enter(ViewChangeEvent event) {
+ log.log("View '" + event.getViewName() + "' not found!");
+ setValue("Tried to navigate to " + event.getViewName()
+ + " but such a view could not be found :(");
+ }
+ }
+
class NaviListener implements ViewChangeListener {
@Override
@@ -114,6 +123,8 @@ public class NavigatorTest extends UI {
navi.addViewChangeListener(new NaviListener());
+ navi.setErrorView(new ErrorView());
+
navi.navigate();
addComponent(new NaviButton("list"));