diff options
author | Leif Åstrand <leif@vaadin.com> | 2012-09-18 15:49:18 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2012-09-18 17:00:39 +0300 |
commit | 25b1dd3c3257e59a6a5ac9554d2a5ad8ea707f6a (patch) | |
tree | d46a2c9634f149ca2e66181b5ba21f1bde28aa2c | |
parent | 83a0a0c124e22fdd832f367d79e7d8a0f5605084 (diff) | |
download | vaadin-framework-25b1dd3c3257e59a6a5ac9554d2a5ad8ea707f6a.tar.gz vaadin-framework-25b1dd3c3257e59a6a5ac9554d2a5ad8ea707f6a.zip |
Replace onVaadinSessionStarted with a listener (#9635)
15 files changed, 636 insertions, 458 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index 61d9792b82..ab28ad291b 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -555,7 +555,8 @@ public class ApplicationConnection { // TODO figure out how client and view size could be used better on // server. screen size can be accessed via Browser object, but other // values currently only via transaction listener. - String parameters = "repaintAll=1&" + nativeBootstrapParameters; + String parameters = ApplicationConstants.URL_PARAMETER_REPAINT_ALL + + "=1&" + nativeBootstrapParameters; return parameters; } diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java index 5832b144ec..a0a59da0ec 100644 --- a/server/src/com/vaadin/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java @@ -126,8 +126,6 @@ public abstract class AbstractCommunicationManager implements Serializable { } } - private static String GET_PARAM_REPAINT_ALL = "repaintAll"; - // flag used in the request to indicate that the security token should be // written to the response private static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken"; @@ -549,7 +547,8 @@ public abstract class AbstractCommunicationManager implements Serializable { boolean repaintAll; final OutputStream out; - repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null); + repaintAll = (request + .getParameter(ApplicationConstants.URL_PARAMETER_REPAINT_ALL) != null); // || (request.getSession().isNew()); FIXME What the h*ll is this?? out = response.getOutputStream(); diff --git a/server/src/com/vaadin/server/AbstractVaadinService.java b/server/src/com/vaadin/server/AbstractVaadinService.java index 7150fdf0da..8990c27dd6 100644 --- a/server/src/com/vaadin/server/AbstractVaadinService.java +++ b/server/src/com/vaadin/server/AbstractVaadinService.java @@ -17,9 +17,21 @@ package com.vaadin.server; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Iterator; +import java.util.Locale; import java.util.ServiceLoader; +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.util.ReflectTools; + /** * Abstract implementation of VaadinService that takes care of those parts that * are common to both servlets and portlets. @@ -29,9 +41,27 @@ import java.util.ServiceLoader; */ public abstract class AbstractVaadinService implements VaadinService { + private static final Method SESSION_INIT_METHOD = ReflectTools.findMethod( + VaadinSessionInitializationListener.class, + "vaadinSessionInitialized", VaadinSessionInitializeEvent.class); + + /** + * @deprecated Only supported for {@link LegacyApplication}. + */ + @Deprecated + public static final String URL_PARAMETER_RESTART_APPLICATION = "restartApplication"; + + /** + * @deprecated Only supported for {@link LegacyApplication}. + */ + @Deprecated + public static final String URL_PARAMETER_CLOSE_APPLICATION = "closeApplication"; + private AddonContext addonContext; private final DeploymentConfiguration deploymentConfiguration; + private final EventRouter eventRouter = new EventRouter(); + /** * Creates a new vaadin service based on a deployment configuration * @@ -90,10 +120,213 @@ public abstract class AbstractVaadinService implements VaadinService { return addonContext; } + /** + * Attempts to find a Vaadin session associated with this request. + * + * @param request + * the request to get a vaadin session for. + * + * @see VaadinSession + * + * @return the vaadin session for the request, or <code>null</code> if no + * session is found and this is a request for which a new session + * shouldn't be created. + */ + public VaadinSession findVaadinSession(WrappedRequest request) + throws ServiceException, SessionExpiredException { + + boolean requestCanCreateApplication = requestCanCreateSession(request); + + /* Find an existing application for this request. */ + VaadinSession session = getExistingSession(request, + requestCanCreateApplication); + + if (session != null) { + /* + * There is an existing application. We can use this as long as the + * user not specifically requested to close or restart it. + */ + + final boolean restartApplication = (request + .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); + final boolean closeApplication = (request + .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); + + if (restartApplication) { + closeApplication(session, request.getWrappedSession(false)); + return createAndRegisterApplication(request); + } else if (closeApplication) { + closeApplication(session, request.getWrappedSession(false)); + return null; + } else { + return session; + } + } + + // No existing application was found + + if (requestCanCreateApplication) { + /* + * If the request is such that it should create a new application if + * one as not found, we do that. + */ + return createAndRegisterApplication(request); + } else { + /* + * The application was not found and a new one should not be + * created. Assume the session has expired. + */ + throw new SessionExpiredException(); + } + + } + + private VaadinSession createAndRegisterApplication(WrappedRequest request) + throws ServiceException { + VaadinSession session = createVaadinSession(request); + + session.storeInSession(request.getWrappedSession()); + + URL applicationUrl; + try { + applicationUrl = getApplicationUrl(request); + } catch (MalformedURLException e) { + throw new ServiceException(e); + } + + // Initial locale comes from the request + Locale locale = request.getLocale(); + session.setLocale(locale); + session.start(new SessionStartEvent(applicationUrl, + getDeploymentConfiguration(), + createCommunicationManager(session))); + + onVaadinSessionStarted(request, session); + + return session; + } + + /** + * Get the base URL that should be used for sending requests back to this + * service. + * <p> + * This is only used to support legacy cases. + * + * @param request + * @return + * @throws MalformedURLException + * + * @deprecated Only used to support {@link LegacyApplication}. + */ + @Deprecated + protected URL getApplicationUrl(WrappedRequest request) + throws MalformedURLException { + return null; + } + + /** + * Create a communication manager to use for the given Vaadin session. + * + * @param session + * the vaadin session for which a new communication manager is + * needed + * @return a new communication manager + */ + protected abstract AbstractCommunicationManager createCommunicationManager( + VaadinSession session); + + /** + * Creates a new vaadin session. + * + * @param request + * @return + * @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; + } + + private void onVaadinSessionStarted(WrappedRequest request, + VaadinSession session) throws ServiceException { + addonContext.fireApplicationStarted(session); + eventRouter.fireEvent(new VaadinSessionInitializeEvent(this, session, + request)); + + try { + ServletPortletHelper.checkUiProviders(session); + } catch (ApplicationClassException e) { + throw new ServiceException(e); + } + } + + private void closeApplication(VaadinSession application, + WrappedSession session) { + if (application == null) { + return; + } + + application.close(); + if (session != null) { + application.removeFromSession(); + } + } + + protected VaadinSession getExistingSession(WrappedRequest request, + boolean allowSessionCreation) throws SessionExpiredException { + + // Ensures that the session is still valid + final WrappedSession session = request + .getWrappedSession(allowSessionCreation); + if (session == null) { + throw new SessionExpiredException(); + } + + VaadinSession sessionApplication = VaadinSession.getForSession(session); + + if (sessionApplication == null) { + return null; + } + + if (!sessionApplication.isRunning()) { + sessionApplication.removeFromSession(); + return null; + } + + return sessionApplication; + } + + /** + * Checks whether it's valid to create a new Vaadin session as a result of + * the given request. + * + * @param request + * the request + * @return <code>true</code> if it's valid to create a new Vaadin session + * for the request; else <code>false</code> + */ + protected abstract boolean requestCanCreateSession(WrappedRequest request); + @Override - public VaadinSession getVaadinSession(WrappedRequest request) { - return (VaadinSession) request.getAttribute(VaadinSession.class - .getName()); + public void addVaadinSessionInitializationListener( + VaadinSessionInitializationListener listener) { + eventRouter.addListener(VaadinSessionInitializeEvent.class, listener, + SESSION_INIT_METHOD); } + @Override + public void removeVaadinSessionInitializationListener( + VaadinSessionInitializationListener listener) { + eventRouter.removeListener(VaadinSessionInitializeEvent.class, + listener, SESSION_INIT_METHOD); + } } diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index afb2d4dae1..f516b4b9a6 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -56,9 +56,6 @@ public interface Constants { + " Widgetset version: %s\n" + "================================================================="; - static final String URL_PARAMETER_RESTART_APPLICATION = "restartApplication"; - static final String URL_PARAMETER_CLOSE_APPLICATION = "closeApplication"; - static final String URL_PARAMETER_REPAINT_ALL = "repaintAll"; static final String URL_PARAMETER_THEME = "theme"; static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode"; diff --git a/server/src/com/vaadin/server/GAEVaadinServlet.java b/server/src/com/vaadin/server/GAEVaadinServlet.java index 98b5f94c6a..42d03274bb 100644 --- a/server/src/com/vaadin/server/GAEVaadinServlet.java +++ b/server/src/com/vaadin/server/GAEVaadinServlet.java @@ -199,8 +199,8 @@ public class GAEVaadinServlet extends VaadinServlet { return; } - final HttpSession session = request - .getSession(requestCanCreateApplication(request, requestType)); + final HttpSession session = request.getSession(getVaadinService() + .requestCanCreateSession(request)); if (session == null) { handleServiceSessionExpired(request, response); cleanSession(request); @@ -292,7 +292,7 @@ public class GAEVaadinServlet extends VaadinServlet { } protected VaadinSession getApplicationContext(HttpServletRequest request, - MemcacheService memcache) { + MemcacheService memcache) throws ServletException { HttpSession session = request.getSession(); String id = AC_BASE + session.getId(); byte[] serializedAC = (byte[]) memcache.get(id); @@ -338,9 +338,14 @@ public class GAEVaadinServlet extends VaadinServlet { + " A new one will be created. ", e); } } - // will create new context if the above did not - return getApplicationContext(session); + // will create new context if the above did not + try { + return getVaadinService().findVaadinSession( + createWrappedRequest(request)); + } catch (Exception e) { + throw new ServletException(e); + } } private boolean isCleanupRequest(HttpServletRequest request) { diff --git a/server/src/com/vaadin/server/LegacyVaadinPortlet.java b/server/src/com/vaadin/server/LegacyVaadinPortlet.java index 067ef888b1..bdc03ff643 100644 --- a/server/src/com/vaadin/server/LegacyVaadinPortlet.java +++ b/server/src/com/vaadin/server/LegacyVaadinPortlet.java @@ -24,6 +24,28 @@ import com.vaadin.server.ServletPortletHelper.ApplicationClassException; public class LegacyVaadinPortlet extends VaadinPortlet { + @Override + public void init() throws PortletException { + super.init(); + + getVaadinService().addVaadinSessionInitializationListener( + new VaadinSessionInitializationListener() { + @Override + public void vaadinSessionInitialized( + VaadinSessionInitializeEvent event) + throws ServiceException { + try { + onVaadinSessionStarted(WrappedPortletRequest + .cast(event.getRequest()), + (VaadinPortletSession) event + .getVaadinSession()); + } catch (PortletException e) { + throw new ServiceException(e); + } + } + }); + } + protected Class<? extends LegacyApplication> getApplicationClass() throws ClassNotFoundException { try { @@ -44,8 +66,7 @@ public class LegacyVaadinPortlet extends VaadinPortlet { } } - @Override - protected void onVaadinSessionStarted(WrappedPortletRequest request, + private void onVaadinSessionStarted(WrappedPortletRequest request, VaadinPortletSession session) throws PortletException { if (shouldCreateApplication(request)) { // Must set current before running init() @@ -59,8 +80,6 @@ public class LegacyVaadinPortlet extends VaadinPortlet { legacyApplication.doInit(); session.addUIProvider(legacyApplication); } - - super.onVaadinSessionStarted(request, session); } protected boolean shouldCreateApplication(WrappedPortletRequest request) { diff --git a/server/src/com/vaadin/server/LegacyVaadinServlet.java b/server/src/com/vaadin/server/LegacyVaadinServlet.java index 4cdb66db44..8d55fddc39 100644 --- a/server/src/com/vaadin/server/LegacyVaadinServlet.java +++ b/server/src/com/vaadin/server/LegacyVaadinServlet.java @@ -16,6 +16,7 @@ package com.vaadin.server; +import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -24,6 +25,26 @@ import com.vaadin.server.ServletPortletHelper.ApplicationClassException; public class LegacyVaadinServlet extends VaadinServlet { + @Override + public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + + getVaadinService().addVaadinSessionInitializationListener( + new VaadinSessionInitializationListener() { + @Override + public void vaadinSessionInitialized( + VaadinSessionInitializeEvent event) + throws ServiceException { + try { + onVaadinSessionStarted(event.getRequest(), + event.getVaadinSession()); + } catch (ServletException e) { + throw new ServiceException(e); + } + } + }); + } + protected Class<? extends LegacyApplication> getApplicationClass() throws ClassNotFoundException { try { @@ -49,9 +70,10 @@ public class LegacyVaadinServlet extends VaadinServlet { return true; } - @Override - protected void onVaadinSessionStarted(WrappedHttpServletRequest request, - VaadinServletSession session) throws ServletException { + private void onVaadinSessionStarted(WrappedRequest wrappedRequest, + VaadinSession session) throws ServletException { + WrappedHttpServletRequest request = WrappedHttpServletRequest + .cast(wrappedRequest); if (shouldCreateApplication(request)) { // Must set current before running init() @@ -64,8 +86,6 @@ public class LegacyVaadinServlet extends VaadinServlet { legacyApplication.doInit(); session.addUIProvider(legacyApplication); } - - super.onVaadinSessionStarted(request, session); } } diff --git a/server/src/com/vaadin/server/ServiceException.java b/server/src/com/vaadin/server/ServiceException.java new file mode 100644 index 0000000000..538e8b30ea --- /dev/null +++ b/server/src/com/vaadin/server/ServiceException.java @@ -0,0 +1,29 @@ +/* + * 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; + +public class ServiceException extends Exception { + + public ServiceException(Exception e) { + super(e); + } + + public ServiceException(String message) { + super(message); + } + +} diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java index 940a4925c8..2da92f729e 100644 --- a/server/src/com/vaadin/server/VaadinPortlet.java +++ b/server/src/com/vaadin/server/VaadinPortlet.java @@ -28,7 +28,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.security.GeneralSecurityException; import java.util.Enumeration; -import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.logging.Level; @@ -44,7 +43,6 @@ import javax.portlet.PortletContext; import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; -import javax.portlet.PortletSession; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; @@ -57,8 +55,6 @@ import com.liferay.portal.kernel.util.PortalClassInvoker; import com.liferay.portal.kernel.util.PropsUtil; import com.vaadin.DefaultDeploymentConfiguration; import com.vaadin.server.AbstractCommunicationManager.Callback; -import com.vaadin.server.ServletPortletHelper.ApplicationClassException; -import com.vaadin.server.VaadinSession.SessionStartEvent; import com.vaadin.ui.UI; import com.vaadin.util.CurrentInstance; @@ -182,6 +178,50 @@ public class VaadinPortlet extends GenericPortlet implements Constants { return null; } + @Override + protected boolean requestCanCreateSession(WrappedRequest request) { + RequestType requestType = getRequestType(request); + if (requestType == RequestType.RENDER) { + // In most cases the first request is a render request that + // renders the HTML fragment. This should create an application + // instance. + return true; + } else if (requestType == RequestType.EVENT) { + // A portlet can also be sent an event even though it has not + // been rendered, e.g. portlet on one page sends an event to a + // portlet on another page and then moves the user to that page. + return true; + } + return false; + } + + /** + * Gets the request type for the request. + * + * @param request + * the request to get a request type for + * @return the request type + * + * @deprecated might be refactored or removed before 7.0.0 + */ + @Deprecated + protected RequestType getRequestType(WrappedRequest request) { + RequestType type = (RequestType) request + .getAttribute(RequestType.class.getName()); + if (type == null) { + type = getPortlet().getRequestType( + WrappedPortletRequest.cast(request)); + request.setAttribute(RequestType.class.getName(), type); + } + return type; + } + + @Override + protected AbstractCommunicationManager createCommunicationManager( + VaadinSession session) { + return new PortletCommunicationManager(session); + } + } public static class WrappedHttpAndPortletRequest extends @@ -360,6 +400,12 @@ public class VaadinPortlet extends GenericPortlet implements Constants { addonContext = new AddonContext(vaadinService); addonContext.init(); + + portletInitialized(); + } + + protected void portletInitialized() { + } protected DeploymentConfiguration createDeploymentConfiguration( @@ -492,8 +538,8 @@ public class VaadinPortlet extends GenericPortlet implements Constants { // TODO What about PARAM_UNLOADBURST & redirectToApplication?? /* Find out which application this request is related to */ - application = findApplicationInstance(wrappedRequest, - requestType); + application = getVaadinService().findVaadinSession( + wrappedRequest); if (application == null) { return; } @@ -767,36 +813,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants { handleRequest(request, response); } - /** - * @param request - * @param requestType - * @return - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - boolean requestCanCreateApplication(PortletRequest request, - RequestType requestType) { - if (requestType == RequestType.UIDL && isRepaintAll(request)) { - return true; - } else if (requestType == RequestType.RENDER) { - // In most cases the first request is a render request that renders - // the HTML fragment. This should create an application instance. - return true; - } else if (requestType == RequestType.EVENT) { - // A portlet can also be sent an event even though it has not been - // rendered, e.g. portlet on one page sends an event to a portlet on - // another page and then moves the user to that page. - return true; - } - return false; - } - - private boolean isRepaintAll(PortletRequest request) { - return (request.getParameter(URL_PARAMETER_REPAINT_ALL) != null) - && (request.getParameter(URL_PARAMETER_REPAINT_ALL).equals("1")); - } - private void endApplication(PortletRequest request, PortletResponse response, VaadinSession application) throws IOException { @@ -804,125 +820,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants { // Do not send any redirects when running inside a portlet. } - private VaadinSession findApplicationInstance( - WrappedPortletRequest wrappedRequest, RequestType requestType) - throws PortletException, SessionExpiredException, - MalformedURLException { - PortletRequest request = wrappedRequest.getPortletRequest(); - - boolean requestCanCreateApplication = requestCanCreateApplication( - request, requestType); - - /* Find an existing application for this request. */ - VaadinSession application = getExistingApplication(request, - requestCanCreateApplication); - - if (application != null) { - /* - * There is an existing application. We can use this as long as the - * user not specifically requested to close or restart it. - */ - - final boolean restartApplication = (wrappedRequest - .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (wrappedRequest - .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); - - if (restartApplication) { - closeApplication(application, request.getPortletSession(false)); - return createAndRegisterApplication(wrappedRequest); - } else if (closeApplication) { - closeApplication(application, request.getPortletSession(false)); - return null; - } else { - return application; - } - } - - // No existing application was found - - if (requestCanCreateApplication) { - return createAndRegisterApplication(wrappedRequest); - } else { - throw new SessionExpiredException(); - } - } - - private void closeApplication(VaadinSession application, - PortletSession session) { - if (application == null) { - return; - } - - application.close(); - application.removeFromSession(); - } - - private VaadinSession createAndRegisterApplication( - WrappedPortletRequest request) throws PortletException { - VaadinPortletSession newApplication = createApplication(); - - newApplication.storeInSession(new WrappedPortletSession(request - .getPortletRequest().getPortletSession())); - - Locale locale = request.getLocale(); - newApplication.setLocale(locale); - // No application URL when running inside a portlet - newApplication.start(new SessionStartEvent(null, getVaadinService() - .getDeploymentConfiguration(), new PortletCommunicationManager( - newApplication))); - onVaadinSessionStarted(request, newApplication); - - return newApplication; - } - - protected void onVaadinSessionStarted(WrappedPortletRequest request, - VaadinPortletSession session) throws PortletException { - addonContext.fireApplicationStarted(session); - try { - ServletPortletHelper.checkUiProviders(session); - } catch (ApplicationClassException e) { - throw new PortletException(e); - } - } - - private VaadinPortletSession createApplication() throws PortletException { - VaadinPortletSession application = new VaadinPortletSession(); - - try { - ServletPortletHelper.initDefaultUIProvider(application, - getVaadinService()); - } catch (ApplicationClassException e) { - throw new PortletException(e); - } - - return application; - } - - private VaadinSession getExistingApplication(PortletRequest request, - boolean allowSessionCreation) throws MalformedURLException, - SessionExpiredException { - - final PortletSession session = request - .getPortletSession(allowSessionCreation); - - if (session == null) { - throw new SessionExpiredException(); - } - - VaadinSession application = VaadinSession - .getForSession(new WrappedPortletSession(session)); - if (application == null) { - return null; - } - if (!application.isRunning()) { - application.removeFromSession(); - return null; - } - - return application; - } - private void handleServiceException(WrappedPortletRequest request, WrappedPortletResponse response, VaadinSession application, Throwable e) throws IOException, PortletException { diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 827902def2..aa8ab9d01d 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -140,16 +140,31 @@ public interface VaadinService extends Serializable { public File getBaseDirectory(); /** - * Gets the Vaadin session associated with this request. - * - * @param request - * the request to get a vaadin session for. + * Adds a listener that gets notified when a new Vaadin session is + * initialized for this service. + * <p> + * Because of the way different service instances share the same session, + * the listener is not necessarily notified immediately when the session is + * created but only when the first request for that session is handled by + * this service. + * + * @see #removeVaadinSessionInitializationListener(VaadinSessionInitializationListener) + * @see VaadinSessionInitializationListener + * + * @param listener + * the vaadin session initialization listener + */ + public void addVaadinSessionInitializationListener( + VaadinSessionInitializationListener listener); + + /** + * Removes a Vaadin session initialization listener from this service. * - * @see VaadinSession + * @see #addVaadinSessionInitializationListener(VaadinSessionInitializationListener) * - * @return the vaadin session for the request, or <code>null</code> if no - * session is found and this is a request for which a new session - * shouldn't be created. + * @param listener + * the Vaadin session initialization listener to remove. */ - public VaadinSession getVaadinSession(WrappedRequest request); + public void removeVaadinSessionInitializationListener( + VaadinSessionInitializationListener listener); } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index fd95852c6a..26a1f511eb 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -31,7 +31,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashSet; -import java.util.Locale; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,8 +46,6 @@ import javax.servlet.http.HttpSession; import com.vaadin.DefaultDeploymentConfiguration; import com.vaadin.sass.ScssStylesheet; import com.vaadin.server.AbstractCommunicationManager.Callback; -import com.vaadin.server.ServletPortletHelper.ApplicationClassException; -import com.vaadin.server.VaadinSession.SessionStartEvent; import com.vaadin.shared.ApplicationConstants; import com.vaadin.ui.UI; import com.vaadin.util.CurrentInstance; @@ -148,6 +145,58 @@ public class VaadinServlet extends HttpServlet implements Constants { } return new File(realPath); } + + @Override + protected boolean requestCanCreateSession(WrappedRequest request) { + RequestType requestType = getRequestType(request); + if (requestType == RequestType.BROWSER_DETAILS) { + // This is the first request if you are embedding by writing the + // embedding code yourself + return true; + } else if (requestType == RequestType.OTHER) { + /* + * I.e URIs that are not application resources or static (theme) + * files. + */ + return true; + } + + return false; + } + + /** + * Gets the request type for the request. + * + * @param request + * the request to get a request type for + * @return the request type + * + * @deprecated might be refactored or removed before 7.0.0 + */ + @Deprecated + protected RequestType getRequestType(WrappedRequest request) { + RequestType type = (RequestType) request + .getAttribute(RequestType.class.getName()); + if (type == null) { + type = getServlet().getRequestType( + WrappedHttpServletRequest.cast(request)); + request.setAttribute(RequestType.class.getName(), type); + } + return type; + } + + @Override + protected URL getApplicationUrl(WrappedRequest request) + throws MalformedURLException { + return getServlet().getApplicationUrl( + WrappedHttpServletRequest.cast(request)); + } + + @Override + protected AbstractCommunicationManager createCommunicationManager( + VaadinSession session) { + return new CommunicationManager(session); + } } private static class AbstractApplicationServletWrapper implements Callback { @@ -216,6 +265,12 @@ public class VaadinServlet extends HttpServlet implements Constants { addonContext = new AddonContext(servletService); addonContext.init(); + + servletInitialized(); + } + + protected void servletInitialized() { + // Empty by default } protected DeploymentConfiguration createDeploymentConfiguration( @@ -297,13 +352,13 @@ public class VaadinServlet extends HttpServlet implements Constants { && request.getParameterMap().containsKey( ApplicationConstants.PARAM_UNLOADBURST) && request.getContentLength() < 1 - && getExistingApplication(request, false) == null) { + && getVaadinService().getExistingSession(request, false) == null) { redirectToApplication(request, response); return; } // Find out which application this request is related to - application = findApplicationInstance(request, requestType); + application = getVaadinService().findVaadinSession(request); if (application == null) { return; } @@ -433,7 +488,7 @@ public class VaadinServlet extends HttpServlet implements Constants { private boolean ensureCookiesEnabled(RequestType requestType, WrappedHttpServletRequest request, WrappedHttpServletResponse response) throws IOException { - if (requestType == RequestType.UIDL && !isRepaintAll(request)) { + if (requestType == RequestType.UIDL) { // In all other but the first UIDL request a cookie should be // returned by the browser. // This can be removed if cookieless mode (#3228) is supported @@ -560,140 +615,6 @@ public class VaadinServlet extends HttpServlet implements Constants { } /** - * Returns the application instance to be used for the request. If an - * existing instance is not found a new one is created or null is returned - * to indicate that the application is not available. - * - * @param request - * @param requestType - * @return - * @throws MalformedURLException - * @throws IllegalAccessException - * @throws InstantiationException - * @throws ServletException - * @throws SessionExpiredException - */ - private VaadinSession findApplicationInstance( - WrappedHttpServletRequest request, RequestType requestType) - throws MalformedURLException, ServletException, - SessionExpiredException { - - boolean requestCanCreateApplication = requestCanCreateApplication( - request, requestType); - - /* Find an existing application for this request. */ - VaadinSession application = getExistingApplication(request, - requestCanCreateApplication); - - if (application != null) { - /* - * There is an existing application. We can use this as long as the - * user not specifically requested to close or restart it. - */ - - final boolean restartApplication = (request - .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (request - .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); - - if (restartApplication) { - closeApplication(application, request.getSession(false)); - return createAndRegisterApplication(request); - } else if (closeApplication) { - closeApplication(application, request.getSession(false)); - return null; - } else { - return application; - } - } - - // No existing application was found - - if (requestCanCreateApplication) { - /* - * If the request is such that it should create a new application if - * one as not found, we do that. - */ - return createAndRegisterApplication(request); - } else { - /* - * The application was not found and a new one should not be - * created. Assume the session has expired. - */ - throw new SessionExpiredException(); - } - - } - - private VaadinSession createAndRegisterApplication( - WrappedHttpServletRequest request) throws ServletException, - MalformedURLException { - VaadinServletSession session = createVaadinSession(request); - - session.storeInSession(new WrappedHttpSession(request.getSession())); - - final URL applicationUrl = getApplicationUrl(request); - - // Initial locale comes from the request - Locale locale = request.getLocale(); - session.setLocale(locale); - session.start(new SessionStartEvent(applicationUrl, getVaadinService() - .getDeploymentConfiguration(), - createCommunicationManager(session))); - - onVaadinSessionStarted(request, session); - - return session; - } - - protected void onVaadinSessionStarted(WrappedHttpServletRequest request, - VaadinServletSession session) throws ServletException { - addonContext.fireApplicationStarted(session); - - try { - ServletPortletHelper.checkUiProviders(session); - } catch (ApplicationClassException e) { - throw new ServletException(e); - } - } - - /** - * Check if the request should create an application if an existing - * application is not found. - * - * @param request - * @param requestType - * @return true if an application should be created, false otherwise - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - boolean requestCanCreateApplication(HttpServletRequest request, - RequestType requestType) { - if (requestType == RequestType.UIDL && isRepaintAll(request)) { - /* - * UIDL request contains valid repaintAll=1 event, the user probably - * wants to initiate a new application through a custom index.html - * without using the bootstrap page. - */ - return true; - } else if (requestType == RequestType.BROWSER_DETAILS) { - // This is the first request if you are embedding by writing the - // embedding code yourself - return true; - } else if (requestType == RequestType.OTHER) { - /* - * I.e URIs that are not application resources or static (theme) - * files. - */ - return true; - - } - - return false; - } - - /** * Gets resource path using different implementations. Required to * supporting different servlet container implementations (application * servers). @@ -725,28 +646,6 @@ public class VaadinServlet extends HttpServlet implements Constants { return resultPath; } - /** - * Creates a new vaadin session. - * - * @param request - * @return - * @throws ServletException - * @throws MalformedURLException - */ - private VaadinServletSession createVaadinSession(HttpServletRequest request) - throws ServletException { - VaadinServletSession session = new VaadinServletSession(); - - try { - ServletPortletHelper.initDefaultUIProvider(session, - getVaadinService()); - } catch (ApplicationClassException e) { - throw new ServletException(e); - } - - return session; - } - private void handleServiceException(WrappedHttpServletRequest request, WrappedHttpServletResponse response, VaadinSession application, Throwable e) throws IOException, ServletException { @@ -1377,51 +1276,6 @@ public class VaadinServlet extends HttpServlet implements Constants { } /** - * Gets the existing application for given request. Looks for application - * instance for given request based on the requested URL. - * - * @param request - * the HTTP request. - * @param allowSessionCreation - * true if a session should be created if no session exists, - * false if no session should be created - * @return Application instance, or null if the URL does not map to valid - * application. - * @throws MalformedURLException - * if the application is denied access to the persistent data - * store represented by the given URL. - * @throws IllegalAccessException - * @throws InstantiationException - * @throws SessionExpiredException - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - protected VaadinSession getExistingApplication(HttpServletRequest request, - boolean allowSessionCreation) throws MalformedURLException, - SessionExpiredException { - - // Ensures that the session is still valid - final HttpSession session = request.getSession(allowSessionCreation); - if (session == null) { - throw new SessionExpiredException(); - } - - VaadinSession sessionApplication = getApplicationContext(session); - - if (sessionApplication == null) { - return null; - } - - if (!sessionApplication.isRunning()) { - sessionApplication.removeFromSession(); - return null; - } - - return sessionApplication; - } - - /** * Ends the application. * * @param request @@ -1490,35 +1344,6 @@ public class VaadinServlet extends HttpServlet implements Constants { return resourcePath + theme + "/" + resource.getResourceId(); } - private boolean isRepaintAll(HttpServletRequest request) { - return (request.getParameter(URL_PARAMETER_REPAINT_ALL) != null) - && (request.getParameter(URL_PARAMETER_REPAINT_ALL).equals("1")); - } - - private void closeApplication(VaadinSession application, HttpSession session) { - if (application == null) { - return; - } - - application.close(); - if (session != null) { - application.removeFromSession(); - } - } - - /** - * @param session - * @return - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - protected VaadinSession getApplicationContext(final HttpSession session) { - VaadinSession sessionApplication = VaadinSession - .getForSession(new WrappedHttpSession(session)); - return sessionApplication; - } - public class RequestError implements Terminal.ErrorEvent, Serializable { private final Throwable throwable; @@ -1535,29 +1360,6 @@ public class VaadinServlet extends HttpServlet implements Constants { } /** - * Override this method if you need to use a specialized communicaiton - * mananger implementation. - * - * @deprecated Instead of overriding this method, override - * {@link VaadinServletSession} implementation via - * {@link VaadinServlet#getApplicationContext(HttpSession)} - * method and in that customized implementation return your - * CommunicationManager in - * {@link VaadinServletSession#getApplicationManager(VaadinSession, VaadinServlet)} - * method. - * - * @param application - * @return - * - * @deprecated might be refactored or removed before 7.0.0 - */ - @Deprecated - public CommunicationManager createCommunicationManager( - VaadinSession application) { - return new CommunicationManager(application); - } - - /** * Escapes characters to html entities. An exception is made for some * "safe characters" to keep the text somewhat readable. * diff --git a/server/src/com/vaadin/server/VaadinSessionInitializationListener.java b/server/src/com/vaadin/server/VaadinSessionInitializationListener.java new file mode 100644 index 0000000000..11b14cc9fc --- /dev/null +++ b/server/src/com/vaadin/server/VaadinSessionInitializationListener.java @@ -0,0 +1,49 @@ +/* + * 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; + +/** + * Event listener that can be registered to a {@link VaadinService} to get an + * event when a new Vaadin session is initialized for that service. + * <p> + * Because of the way different service instances share the same session, the + * listener is not necessarily notified immediately when the session is created + * but only when the first request for that session is handled by a specific + * service. + * + * @see VaadinService#addVaadinSessionInitializationListener(VaadinSessionInitializationListener) + * + * @author Vaadin Ltd + * @since 7.0.0 + */ +public interface VaadinSessionInitializationListener { + /** + * Invoked when a new Vaadin session is initialized for that service. + * <p> + * Because of the way different service instances share the same session, + * the listener is not necessarily notified immediately when the session is + * created but only when the first request for that session is handled by a + * specific service. + * + * @param event + * the initialization event + * @throws ServiceException + * a problem occurs when processing the event + */ + public void vaadinSessionInitialized(VaadinSessionInitializeEvent event) + throws ServiceException; +} diff --git a/server/src/com/vaadin/server/VaadinSessionInitializeEvent.java b/server/src/com/vaadin/server/VaadinSessionInitializeEvent.java new file mode 100644 index 0000000000..cc4a0990d6 --- /dev/null +++ b/server/src/com/vaadin/server/VaadinSessionInitializeEvent.java @@ -0,0 +1,89 @@ +/* + * 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 gets fired when a new Vaadin session is initialized for a Vaadin + * service. + * <p> + * Because of the way different service instances share the same session, the + * event is not necessarily fired immediately when the session is created but + * only when the first request for that session is handled by a specific + * service. + * + * @see VaadinSessionInitializationListener#vaadinSessionInitialized(VaadinSessionInitializeEvent) + * + * @author Vaadin Ltd + * @since 7.0.0 + */ +public class VaadinSessionInitializeEvent extends EventObject { + + private final VaadinSession session; + private final WrappedRequest request; + + /** + * Creates a new event. + * + * @param service + * the Vaadin service from which the event originates + * @param session + * the Vaadin session that has been initialized + * @param request + * the request that triggered the initialization + */ + public VaadinSessionInitializeEvent(VaadinService service, + VaadinSession session, WrappedRequest request) { + super(service); + this.session = session; + this.request = request; + } + + @Override + public VaadinService getSource() { + return (VaadinService) super.getSource(); + } + + /** + * Gets the Vaadin service from which this event originates + * + * @return the Vaadin service instance + */ + public VaadinService getVaadinService() { + return getSource(); + } + + /** + * Gets the Vaadin session that has been initialized. + * + * @return the Vaadin session + */ + public VaadinSession getVaadinSession() { + return session; + } + + /** + * Gets the request that triggered the initialization. + * + * @return the request + */ + public WrappedRequest getRequest() { + return request; + } + +} diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java index 0bacd2d256..2c0c0c4af0 100644 --- a/shared/src/com/vaadin/shared/ApplicationConstants.java +++ b/shared/src/com/vaadin/shared/ApplicationConstants.java @@ -45,4 +45,11 @@ public class ApplicationConstants { @Deprecated public static final String DRAG_AND_DROP_CONNECTOR_ID = "DD"; + + /** + * URL parameter used in UIDL requests to indicate that the full server-side + * state should be returned to the client, i.e. without any incremental + * changes. + */ + public static final String URL_PARAMETER_REPAINT_ALL = "repaintAll"; } diff --git a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java index 032957bffc..f31b17333a 100644 --- a/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java +++ b/uitest/src/com/vaadin/launcher/ApplicationRunnerServlet.java @@ -33,8 +33,11 @@ import com.vaadin.LegacyApplication; import com.vaadin.server.AbstractUIProvider; import com.vaadin.server.DeploymentConfiguration; import com.vaadin.server.LegacyVaadinServlet; +import com.vaadin.server.ServiceException; import com.vaadin.server.UIProvider; -import com.vaadin.server.VaadinServletSession; +import com.vaadin.server.VaadinSession; +import com.vaadin.server.VaadinSessionInitializationListener; +import com.vaadin.server.VaadinSessionInitializeEvent; import com.vaadin.server.WrappedHttpServletRequest; import com.vaadin.server.WrappedRequest; import com.vaadin.tests.components.TestBase; @@ -69,6 +72,21 @@ public class ApplicationRunnerServlet extends LegacyVaadinServlet { } } + @Override + protected void servletInitialized() { + super.servletInitialized(); + getVaadinService().addVaadinSessionInitializationListener( + new VaadinSessionInitializationListener() { + @Override + public void vaadinSessionInitialized( + VaadinSessionInitializeEvent event) + throws ServiceException { + onVaadinSessionStarted(event.getRequest(), + event.getVaadinSession()); + } + }); + } + private void addDirectories(File parent, LinkedHashSet<String> packages, String parentPackage) { packages.add(parentPackage); @@ -120,9 +138,8 @@ public class ApplicationRunnerServlet extends LegacyVaadinServlet { } } - @Override - protected void onVaadinSessionStarted(WrappedHttpServletRequest request, - VaadinServletSession session) throws ServletException { + protected void onVaadinSessionStarted(WrappedRequest request, + VaadinSession session) throws ServiceException { try { final Class<?> classToRun = getClassToRun(); if (UI.class.isAssignableFrom(classToRun)) { @@ -138,21 +155,20 @@ public class ApplicationRunnerServlet extends LegacyVaadinServlet { } else if (UIProvider.class.isAssignableFrom(classToRun)) { session.addUIProvider((UIProvider) classToRun.newInstance()); } else { - throw new ServletException(classToRun.getCanonicalName() + throw new ServiceException(classToRun.getCanonicalName() + " is neither an Application nor a UI"); } } catch (final IllegalAccessException e) { - throw new ServletException(e); + throw new ServiceException(e); } catch (final InstantiationException e) { - throw new ServletException(e); + throw new ServiceException(e); } catch (final ClassNotFoundException e) { - throw new ServletException( + throw new ServiceException( new InstantiationException( "Failed to load application class: " - + getApplicationRunnerApplicationClassName(request))); + + getApplicationRunnerApplicationClassName(WrappedHttpServletRequest + .cast(request)))); } - - super.onVaadinSessionStarted(request, session); } private String getApplicationRunnerApplicationClassName( |