@@ -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; | |||
} | |||
} |
@@ -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("}]"); | |||
} |
@@ -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(); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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}. | |||
*/ | |||
@@ -253,6 +259,44 @@ public abstract class VaadinService implements Serializable { | |||
listener, SESSION_INIT_METHOD); | |||
} | |||
/** | |||
* 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. | |||
* | |||
@@ -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; | |||
} | |||
@@ -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; | |||
} | |||
@@ -1347,35 +1339,6 @@ public class VaadinServlet extends HttpServlet implements Constants { | |||
return u; | |||
} | |||
/** | |||
* 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: |
@@ -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; | |||
@@ -153,22 +154,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; | |||
} | |||
/** | |||
@@ -301,25 +305,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { | |||
return applicationUrl; | |||
} | |||
/** | |||
* 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; | |||
} | |||
/** | |||
@@ -566,41 +532,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { | |||
public void windowDetached(WindowDetachEvent event); | |||
} | |||
/** | |||
* 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. | |||
* | |||
@@ -1180,18 +1111,34 @@ 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"); | |||
} | |||
} | |||
} | |||
/** | |||
* 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 |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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()); |
@@ -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); |
@@ -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(); | |||
} | |||
}); | |||
@@ -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(); | |||
} | |||
}); | |||