diff options
Diffstat (limited to 'server/src/com')
18 files changed, 968 insertions, 608 deletions
diff --git a/server/src/com/vaadin/navigator/Navigator.java b/server/src/com/vaadin/navigator/Navigator.java index d3098903c5..257dfa208f 100644 --- a/server/src/com/vaadin/navigator/Navigator.java +++ b/server/src/com/vaadin/navigator/Navigator.java @@ -29,6 +29,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.CssLayout; import com.vaadin.ui.CustomComponent; +import com.vaadin.ui.UI; /** * A navigator utility that allows switching of views in a part of an @@ -124,7 +125,7 @@ public class Navigator implements Serializable { @Override public void fragmentChanged(FragmentChangedEvent event) { - UriFragmentManager.this.navigator.navigateTo(getState()); + navigator.navigateTo(getState()); } } @@ -331,6 +332,7 @@ public class Navigator implements Serializable { } } + private final UI ui; private final NavigationStateManager stateManager; private final ViewDisplay display; private View currentView = null; @@ -354,30 +356,34 @@ public class Navigator implements Serializable { * the application should trigger navigation to the current fragment using * {@link #navigate()}. * + * @param ui + * The UI to which this Navigator is attached. * @param container - * ComponentContainer whose contents should be replaced with the - * active view on view change + * The ComponentContainer whose contents should be replaced with + * the active view on view change */ - public Navigator(ComponentContainer container) { - display = new ComponentContainerViewDisplay(container); - stateManager = new UriFragmentManager(Page.getCurrent(), this); + public Navigator(UI ui, ComponentContainer container) { + this(ui, new ComponentContainerViewDisplay(container)); } /** - * Creates a navigator that is tracking the active view using URI fragments. + * Creates a navigator that is tracking the active view using URI fragments + * of the Page containing the given UI. * <p> * After all {@link View}s and {@link ViewProvider}s have been registered, * the application should trigger navigation to the current fragment using * {@link #navigate()}. * - * @param page - * whose URI fragments are used + * @param ui + * The UI to which this Navigator is attached. * @param display - * where to display the views + * The ViewDisplay used to display the views. */ - public Navigator(Page page, ViewDisplay display) { + public Navigator(UI ui, ViewDisplay display) { + this.ui = ui; + this.ui.setNavigator(this); this.display = display; - stateManager = new UriFragmentManager(page, this); + stateManager = new UriFragmentManager(ui.getPage(), this); } /** @@ -391,14 +397,19 @@ public class Navigator implements Serializable { * the application should trigger navigation to the current fragment using * {@link #navigate()}. * + * @param ui + * The UI to which this Navigator is attached. * @param stateManager - * {@link NavigationStateManager} keeping track of the active - * view and enabling bookmarking and direct navigation + * The NavigationStateManager keeping track of the active view + * and enabling bookmarking and direct navigation * @param display - * {@ViewDisplay} used to display the views handled - * by this navigator + * The ViewDisplay used to display the views handled by this + * navigator */ - public Navigator(NavigationStateManager stateManager, ViewDisplay display) { + public Navigator(UI ui, NavigationStateManager stateManager, + ViewDisplay display) { + this.ui = ui; + this.ui.setNavigator(this); this.display = display; this.stateManager = stateManager; } @@ -547,6 +558,10 @@ public class Navigator implements Serializable { return display; } + public UI getUI() { + return ui; + } + /** * Fires an event after the current view has changed. * <p> diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java index 5832b144ec..9ac33df7d2 100644 --- a/server/src/com/vaadin/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/server/AbstractCommunicationManager.java @@ -84,6 +84,7 @@ import com.vaadin.ui.ConnectorTracker; import com.vaadin.ui.HasComponents; import com.vaadin.ui.UI; import com.vaadin.ui.Window; +import com.vaadin.util.CurrentInstance; /** * This is a common base class for the server-side implementations of the @@ -126,8 +127,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 +548,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(); @@ -2470,6 +2470,7 @@ public abstract class AbstractCommunicationManager implements Serializable { assert UI.getCurrent() == null; CombinedRequest combinedRequest = new CombinedRequest(request); + CurrentInstance.set(WrappedRequest.class, combinedRequest); response.setContentType("application/json; charset=UTF-8"); diff --git a/server/src/com/vaadin/server/AbstractVaadinService.java b/server/src/com/vaadin/server/AbstractVaadinService.java deleted file mode 100644 index 7150fdf0da..0000000000 --- a/server/src/com/vaadin/server/AbstractVaadinService.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.lang.reflect.Constructor; -import java.util.Iterator; -import java.util.ServiceLoader; - -/** - * Abstract implementation of VaadinService that takes care of those parts that - * are common to both servlets and portlets. - * - * @author Vaadin Ltd - * @since 7.0.0 - */ -public abstract class AbstractVaadinService implements VaadinService { - - private AddonContext addonContext; - private final DeploymentConfiguration deploymentConfiguration; - - /** - * Creates a new vaadin service based on a deployment configuration - * - * @param deploymentConfiguration - * the deployment configuration for the service - */ - public AbstractVaadinService(DeploymentConfiguration deploymentConfiguration) { - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - @Override - public ClassLoader getClassLoader() { - final String classLoaderName = getDeploymentConfiguration() - .getApplicationOrSystemProperty("ClassLoader", null); - ClassLoader classLoader; - if (classLoaderName == null) { - classLoader = getClass().getClassLoader(); - } else { - try { - final Class<?> classLoaderClass = getClass().getClassLoader() - .loadClass(classLoaderName); - final Constructor<?> c = classLoaderClass - .getConstructor(new Class[] { ClassLoader.class }); - classLoader = (ClassLoader) c - .newInstance(new Object[] { getClass().getClassLoader() }); - } catch (final Exception e) { - throw new RuntimeException( - "Could not find specified class loader: " - + classLoaderName, e); - } - } - return classLoader; - } - - @Override - public Iterator<AddonContextListener> getAddonContextListeners() { - // Called once for init and then no more, so there's no point in caching - // the instance - ServiceLoader<AddonContextListener> contextListenerLoader = ServiceLoader - .load(AddonContextListener.class, getClassLoader()); - return contextListenerLoader.iterator(); - } - - @Override - public void setAddonContext(AddonContext addonContext) { - this.addonContext = addonContext; - } - - @Override - public AddonContext getAddonContext() { - return addonContext; - } - - @Override - public VaadinSession getVaadinSession(WrappedRequest request) { - return (VaadinSession) request.getAttribute(VaadinSession.class - .getName()); - } - -} 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/DeploymentConfiguration.java b/server/src/com/vaadin/server/DeploymentConfiguration.java index 0333091632..09405d6004 100644 --- a/server/src/com/vaadin/server/DeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DeploymentConfiguration.java @@ -59,15 +59,15 @@ public interface DeploymentConfiguration extends Serializable { /** * Returns whether UIs that have no other activity than heartbeat requests - * should be closed after they have been idle the maximum inactivity time - * enforced by the session. + * should be removed from the session after they have been idle the maximum + * inactivity time enforced by the session. * * @see WrappedSession#getMaxInactiveInterval() * * @since 7.0.0 * * @return True if UIs receiving only heartbeat requests are eventually - * closed; false if heartbeat requests extend UI lifetime + * removed; false if heartbeat requests extend UI lifetime * indefinitely. */ public boolean isIdleUICleanupEnabled(); 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..dc1f93b2a8 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; @@ -78,7 +74,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { @Deprecated public static final String RESOURCE_URL_ID = "APP"; - public static class PortletService extends AbstractVaadinService { + public static class PortletService extends VaadinService { private final VaadinPortlet portlet; public PortletService(VaadinPortlet portlet, @@ -182,6 +178,63 @@ 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 WrappedPortletRequest getCurrentRequest() { + WrappedRequest currentRequest = VaadinService.getCurrentRequest(); + try { + return WrappedPortletRequest.cast(currentRequest); + } catch (ClassCastException e) { + return null; + } + } + + public static WrappedPortletResponse getCurrentResponse() { + return (WrappedPortletResponse) VaadinService.getCurrentResponse(); + } + } public static class WrappedHttpAndPortletRequest extends @@ -337,6 +390,8 @@ public class VaadinPortlet extends GenericPortlet implements Constants { @Override public void init(PortletConfig config) throws PortletException { + CurrentInstance.clearAll(); + setCurrent(this); super.init(config); Properties initParameters = new Properties(); @@ -357,9 +412,18 @@ public class VaadinPortlet extends GenericPortlet implements Constants { DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(initParameters); vaadinService = createPortletService(deploymentConfiguration); + // Sets current service even though there are no request and response + vaadinService.setCurrentInstances(null, null); addonContext = new AddonContext(vaadinService); addonContext.init(); + + portletInitialized(); + CurrentInstance.clearAll(); + } + + protected void portletInitialized() { + } protected DeploymentConfiguration createDeploymentConfiguration( @@ -453,6 +517,9 @@ public class VaadinPortlet extends GenericPortlet implements Constants { RequestTimer requestTimer = new RequestTimer(); requestTimer.start(); + CurrentInstance.clearAll(); + setCurrent(this); + AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( this); @@ -461,8 +528,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( response, getVaadinService()); - CurrentInstance.set(WrappedRequest.class, wrappedRequest); - CurrentInstance.set(WrappedResponse.class, wrappedResponse); + getVaadinService().setCurrentInstances(wrappedRequest, wrappedResponse); RequestType requestType = getRequestType(wrappedRequest); @@ -492,8 +558,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; } @@ -621,7 +687,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants { } finally { if (applicationRunning) { - application.closeInactiveUIs(); + application.cleanupInactiveUIs(); } CurrentInstance.clearAll(); @@ -767,36 +833,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 +840,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 { @@ -1031,4 +948,43 @@ public class VaadinPortlet extends GenericPortlet implements Constants { return Logger.getLogger(VaadinPortlet.class.getName()); } + /** + * Gets the currently used Vaadin portlet. The current portlet is + * automatically defined when initializing the portlet and when processing + * requests to the server and in threads started at a point when the current + * portlet is defined (see {@link InheritableThreadLocal}). In other cases, + * (e.g. from background threads started in some other way), the current + * portlet is not automatically defined. + * + * @return the current vaadin portlet instance if available, otherwise + * <code>null</code> + * + * @see #setCurrent(VaadinPortlet) + * + * @since 7.0 + */ + public static VaadinPortlet getCurrent() { + return CurrentInstance.get(VaadinPortlet.class); + } + + /** + * Sets the current Vaadin portlet. This method is used by the framework to + * set the current portlet whenever a new request is processed and it is + * cleared when the request has been processed. + * <p> + * The application developer can also use this method to define the current + * portlet outside the normal request handling, e.g. when initiating custom + * background threads. + * </p> + * + * @param portlet + * the Vaadin portlet to register as the current portlet + * + * @see #getCurrent() + * @see InheritableThreadLocal + */ + public static void setCurrent(VaadinPortlet portlet) { + CurrentInstance.setInheritable(VaadinPortlet.class, portlet); + } + } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 827902def2..80590df4a0 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -18,10 +18,24 @@ package com.vaadin.server; import java.io.File; import java.io.Serializable; +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.portlet.PortletContext; import javax.servlet.ServletContext; +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.CurrentInstance; +import com.vaadin.util.ReflectTools; /** * Provide deployment specific settings that are required outside terminal @@ -31,7 +45,39 @@ import javax.servlet.ServletContext; * * @since 7.0 */ -public interface VaadinService extends Serializable { +public abstract class VaadinService implements Serializable { + + 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 + * + * @param deploymentConfiguration + * the deployment configuration for the service + */ + public VaadinService(DeploymentConfiguration deploymentConfiguration) { + this.deploymentConfiguration = deploymentConfiguration; + } + /** * Return the URL from where static files, e.g. the widgetset and the theme, * are served. In a standard configuration the VAADIN folder inside the @@ -46,7 +92,7 @@ public interface VaadinService extends Serializable { * @return The location of static resources (should contain the VAADIN * directory). Never ends with a slash (/). */ - public String getStaticFileLocation(WrappedRequest request); + public abstract String getStaticFileLocation(WrappedRequest request); /** * Gets the widgetset that is configured for this deployment, e.g. from a @@ -56,7 +102,7 @@ public interface VaadinService extends Serializable { * the request for which a widgetset is required * @return the name of the widgetset */ - public String getConfiguredWidgetset(WrappedRequest request); + public abstract String getConfiguredWidgetset(WrappedRequest request); /** * Gets the theme that is configured for this deployment, e.g. from a portal @@ -66,7 +112,7 @@ public interface VaadinService extends Serializable { * the request for which a theme is required * @return the name of the theme */ - public String getConfiguredTheme(WrappedRequest request); + public abstract String getConfiguredTheme(WrappedRequest request); /** * Checks whether the Vaadin application will be rendered on its own in the @@ -79,7 +125,7 @@ public interface VaadinService extends Serializable { * the request for which the application is loaded * @return a boolean indicating whether the application should be standalone */ - public boolean isStandalone(WrappedRequest request); + public abstract boolean isStandalone(WrappedRequest request); /** * Get the class loader to use for loading classes loaded by name, e.g. @@ -88,7 +134,28 @@ public interface VaadinService extends Serializable { * * @return the class loader to use, or <code>null</code> */ - public ClassLoader getClassLoader(); + public ClassLoader getClassLoader() { + final String classLoaderName = getDeploymentConfiguration() + .getApplicationOrSystemProperty("ClassLoader", null); + ClassLoader classLoader; + if (classLoaderName == null) { + classLoader = getClass().getClassLoader(); + } else { + try { + final Class<?> classLoaderClass = getClass().getClassLoader() + .loadClass(classLoaderName); + final Constructor<?> c = classLoaderClass + .getConstructor(new Class[] { ClassLoader.class }); + classLoader = (ClassLoader) c + .newInstance(new Object[] { getClass().getClassLoader() }); + } catch (final Exception e) { + throw new RuntimeException( + "Could not find specified class loader: " + + classLoaderName, e); + } + } + return classLoader; + } /** * Returns the MIME type of the specified file, or null if the MIME type is @@ -103,27 +170,39 @@ public interface VaadinService extends Serializable { * @see ServletContext#getMimeType(String) * @see PortletContext#getMimeType(String) */ - public String getMimeType(String resourceName); + public abstract String getMimeType(String resourceName); /** * Gets the deployment configuration. * * @return the deployment configuration */ - public DeploymentConfiguration getDeploymentConfiguration(); + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } - public Iterator<AddonContextListener> getAddonContextListeners(); + public Iterator<AddonContextListener> getAddonContextListeners() { + // Called once for init and then no more, so there's no point in caching + // the instance + ServiceLoader<AddonContextListener> contextListenerLoader = ServiceLoader + .load(AddonContextListener.class, getClassLoader()); + return contextListenerLoader.iterator(); + } - public AddonContext getAddonContext(); + public AddonContext getAddonContext() { + return addonContext; + } - public void setAddonContext(AddonContext vaadinContext); + public void setAddonContext(AddonContext addonContext) { + this.addonContext = addonContext; + } /** * Gets the system messages object * * @return the system messages object */ - public SystemMessages getSystemMessages(); + public abstract SystemMessages getSystemMessages(); /** * Returns application context base directory. @@ -137,10 +216,45 @@ public interface VaadinService extends Serializable { * @return The application base directory or null if the application has no * base directory. */ - public File getBaseDirectory(); + public abstract File getBaseDirectory(); + + /** + * 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) { + eventRouter.addListener(VaadinSessionInitializeEvent.class, listener, + SESSION_INIT_METHOD); + } /** - * Gets the Vaadin session associated with this request. + * Removes a Vaadin session initialization listener from this service. + * + * @see #addVaadinSessionInitializationListener(VaadinSessionInitializationListener) + * + * @param listener + * the Vaadin session initialization listener to remove. + */ + public void removeVaadinSessionInitializationListener( + VaadinSessionInitializationListener listener) { + eventRouter.removeListener(VaadinSessionInitializeEvent.class, + listener, SESSION_INIT_METHOD); + } + + /** + * Attempts to find a Vaadin session associated with this request. * * @param request * the request to get a vaadin session for. @@ -151,5 +265,265 @@ public interface VaadinService extends Serializable { * session is found and this is a request for which a new session * shouldn't be created. */ - public VaadinSession getVaadinSession(WrappedRequest request); + 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); + + /** + * Gets the currently used Vaadin service. The current service is + * automatically defined when processing requests related to the service and + * in threads started at a point when the current service is defined (see + * {@link InheritableThreadLocal}). In other cases, (e.g. from background + * threads started in some other way), the current service is not + * automatically defined. + * + * @return the current Vaadin service instance if available, otherwise + * <code>null</code> + * + * @see #setCurrentInstances(WrappedRequest, WrappedResponse) + */ + public static VaadinService getCurrent() { + return CurrentInstance.get(VaadinService.class); + } + + /** + * Sets the this Vaadin service as the current service and also sets the + * current wrapped request and wrapped response. This method is used by the + * framework to set the current instances when a request related to the + * service is processed and they are cleared when the request has been + * processed. + * <p> + * The application developer can also use this method to define the current + * instances outside the normal request handling, e.g. when initiating + * custom background threads. + * </p> + * + * @param request + * the wrapped request to set as the current request, or + * <code>null</code> if no request should be set. + * @param response + * the wrapped response to set as the current response, or + * <code>null</code> if no response should be set. + * + * @see #getCurrent() + * @see #getCurrentRequest() + * @see #getCurrentResponse() + */ + public void setCurrentInstances(WrappedRequest request, + WrappedResponse response) { + CurrentInstance.setInheritable(VaadinService.class, this); + CurrentInstance.set(WrappedRequest.class, request); + CurrentInstance.set(WrappedResponse.class, response); + } + + /** + * Gets the currently processed wrapped request. The current request is + * automatically defined when the request is started. The current request + * can not be used in e.g. background threads because of the way server + * implementations reuse request instances. + * + * @return the current wrapped request instance if available, otherwise + * <code>null</code> + * + * @see #setCurrentInstances(WrappedRequest, WrappedResponse) + */ + public static WrappedRequest getCurrentRequest() { + return CurrentInstance.get(WrappedRequest.class); + } + + /** + * Gets the currently processed wrapped request. The current request is + * automatically defined when the request is started. The current request + * can not be used in e.g. background threads because of the way server + * implementations reuse request instances. + * + * @return the current wrapped request instance if available, otherwise + * <code>null</code> + * + * @see #setCurrentInstances(WrappedRequest, WrappedResponse) + */ + public static WrappedResponse getCurrentResponse() { + return CurrentInstance.get(WrappedResponse.class); + } + } diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index fd95852c6a..c42d029dc4 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; @@ -56,7 +53,7 @@ import com.vaadin.util.CurrentInstance; @SuppressWarnings("serial") public class VaadinServlet extends HttpServlet implements Constants { - public static class ServletService extends AbstractVaadinService { + public static class ServletService extends VaadinService { private final VaadinServlet servlet; public ServletService(VaadinServlet servlet, @@ -148,6 +145,72 @@ 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); + } + + public static WrappedHttpServletRequest getCurrentRequest() { + WrappedRequest currentRequest = VaadinService.getCurrentRequest(); + try { + return WrappedHttpServletRequest.cast(currentRequest); + } catch (ClassCastException e) { + return null; + } + } + + public static WrappedHttpServletResponse getCurrentResponse() { + return (WrappedHttpServletResponse) VaadinService + .getCurrentResponse(); + } } private static class AbstractApplicationServletWrapper implements Callback { @@ -192,6 +255,8 @@ public class VaadinServlet extends HttpServlet implements Constants { @Override public void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException { + CurrentInstance.clearAll(); + setCurrent(this); super.init(servletConfig); Properties initParameters = new Properties(); @@ -213,9 +278,58 @@ public class VaadinServlet extends HttpServlet implements Constants { DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(initParameters); servletService = createServletService(deploymentConfiguration); + // Sets current service even though there are no request and response + servletService.setCurrentInstances(null, null); addonContext = new AddonContext(servletService); addonContext.init(); + + servletInitialized(); + + CurrentInstance.clearAll(); + } + + protected void servletInitialized() { + // Empty by default + } + + /** + * Gets the currently used Vaadin servlet. The current servlet is + * automatically defined when initializing the servlet and when processing + * requests to the server and in threads started at a point when the current + * servlet is defined (see {@link InheritableThreadLocal}). In other cases, + * (e.g. from background threads started in some other way), the current + * servlet is not automatically defined. + * + * @return the current Vaadin servlet instance if available, otherwise + * <code>null</code> + * + * @see #setCurrent(VaadinServlet) + * + * @since 7.0 + */ + public static VaadinServlet getCurrent() { + return CurrentInstance.get(VaadinServlet.class); + } + + /** + * Sets the current Vaadin servlet. This method is used by the framework to + * set the current servlet whenever a new request is processed and it is + * cleared when the request has been processed. + * <p> + * The application developer can also use this method to define the current + * servlet outside the normal request handling, e.g. when initiating custom + * background threads. + * </p> + * + * @param servlet + * the Vaadin servlet to register as the current servlet + * + * @see #getCurrent() + * @see InheritableThreadLocal + */ + public static void setCurrent(VaadinServlet servlet) { + CurrentInstance.setInheritable(VaadinServlet.class, servlet); } protected DeploymentConfiguration createDeploymentConfiguration( @@ -255,6 +369,8 @@ public class VaadinServlet extends HttpServlet implements Constants { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + CurrentInstance.clearAll(); + setCurrent(this); service(createWrappedRequest(request), createWrappedResponse(response)); } @@ -264,8 +380,7 @@ public class VaadinServlet extends HttpServlet implements Constants { RequestTimer requestTimer = new RequestTimer(); requestTimer.start(); - CurrentInstance.set(WrappedResponse.class, response); - CurrentInstance.set(WrappedRequest.class, request); + getVaadinService().setCurrentInstances(request, response); AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( this); @@ -297,13 +412,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; } @@ -376,7 +491,7 @@ public class VaadinServlet extends HttpServlet implements Constants { } finally { if (applicationRunning) { - application.closeInactiveUIs(); + application.cleanupInactiveUIs(); } CurrentInstance.clearAll(); @@ -433,7 +548,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 +675,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 +706,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 +1336,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 +1404,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 +1420,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/VaadinServletSession.java b/server/src/com/vaadin/server/VaadinServletSession.java index b2e3b9f54c..b2dc84d857 100644 --- a/server/src/com/vaadin/server/VaadinServletSession.java +++ b/server/src/com/vaadin/server/VaadinServletSession.java @@ -23,7 +23,7 @@ import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; -import com.vaadin.util.CurrentInstance; +import com.vaadin.server.VaadinServlet.ServletService; /** * Web application context for Vaadin applications. @@ -58,6 +58,12 @@ public class VaadinServletSession extends VaadinSession { * to avoid session fixation attacks. */ public void reinitializeSession() { + WrappedHttpServletRequest currentRequest = ServletService + .getCurrentRequest(); + if (currentRequest == null) { + throw new IllegalStateException( + "Can not reinitialize session outside normal request handling."); + } HttpSession oldSession = getHttpSession(); @@ -77,8 +83,7 @@ public class VaadinServletSession extends VaadinSession { reinitializingSession = false; // Create a new session - HttpSession newSession = WrappedHttpServletRequest.cast( - CurrentInstance.get(WrappedRequest.class)).getSession(); + HttpSession newSession = currentRequest.getSession(); // Restores all attributes (security key, reference to this context // instance) diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 35a53fc6db..f1d4ab343a 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -316,7 +316,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { public void close() { applicationIsRunning = false; for (UI ui : getUIs()) { - ui.fireCloseEvent(); + ui.fireCleanupEvent(); } } @@ -1166,12 +1166,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Removes all those UIs from the session for which {@link #isUIAlive} - * returns false. Close events are fired for the removed UIs. + * returns false. Cleanup events are fired for the removed UIs. * <p> * Called by the framework at the end of every request. * - * @see UI.CloseEvent - * @see UI.CloseListener + * @see UI.CleanupEvent + * @see UI.CleanupListener * @see #isUIAlive(UI) * * @since 7.0.0 @@ -1179,13 +1179,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * @deprecated might be refactored or removed before 7.0.0 */ @Deprecated - public void closeInactiveUIs() { + public void cleanupInactiveUIs() { for (Iterator<UI> i = uIs.values().iterator(); i.hasNext();) { UI ui = i.next(); if (!isUIAlive(ui)) { i.remove(); retainOnRefreshUIs.values().remove(ui.getUIId()); - ui.fireCloseEvent(); + ui.fireCleanupEvent(); getLogger().fine( "Closed UI #" + ui.getUIId() + " due to inactivity"); } @@ -1200,7 +1200,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * timeout never occurs. * * @see #getUidlRequestTimeout() - * @see #closeInactiveUIs() + * @see #cleanupInactiveUIs() * @see DeploymentConfiguration#getHeartbeatInterval() * * @since 7.0.0 @@ -1225,7 +1225,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * * @see DeploymentConfiguration#isIdleUICleanupEnabled() * @see #getHeartbeatTimeout() - * @see #closeInactiveUIs() + * @see #cleanupInactiveUIs() * * @since 7.0.0 * 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/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java index 8b5cd87648..9434e92186 100644 --- a/server/src/com/vaadin/ui/Label.java +++ b/server/src/com/vaadin/ui/Label.java @@ -170,6 +170,16 @@ public class Label extends AbstractComponent implements Property<String>, // Use internal value if we are running without a data source return getState().text; } + return getDataSourceValue(); + } + + /** + * Returns the current value of the data source. Assumes there is a data + * source. + * + * @return + */ + private String getDataSourceValue() { return ConverterUtil.convertFromModel(getPropertyDataSource() .getValue(), String.class, getConverter(), getLocale()); } @@ -250,14 +260,20 @@ public class Label extends AbstractComponent implements Property<String>, ((Property.ValueChangeNotifier) dataSource).removeListener(this); } - if (!ConverterUtil.canConverterHandle(getConverter(), String.class, - newDataSource.getType())) { + if (newDataSource != null + && !ConverterUtil.canConverterHandle(getConverter(), + String.class, newDataSource.getType())) { // Try to find a converter Converter<String, ?> c = ConverterUtil.getConverter(String.class, newDataSource.getType(), getSession()); setConverter(c); } dataSource = newDataSource; + if (dataSource != null) { + // Update the value from the data source. If data source was set to + // null, retain the old value + getState().text = getDataSourceValue(); + } // Listens the new data source if possible if (dataSource != null diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 3ad0cc57fa..b15a83cdce 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -33,6 +33,7 @@ import com.vaadin.event.Action.Handler; import com.vaadin.event.ActionManager; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; +import com.vaadin.navigator.Navigator; import com.vaadin.server.LegacyComponent; import com.vaadin.server.Page; import com.vaadin.server.Page.BrowserWindowResizeEvent; @@ -411,11 +412,11 @@ public abstract class UI extends AbstractComponentContainer implements /** * Event fired when a UI is removed from the application. */ - public static class CloseEvent extends Event { + public static class CleanupEvent extends Event { - private static final String CLOSE_EVENT_IDENTIFIER = "uiClose"; + private static final String CLEANUP_EVENT_IDENTIFIER = "uiCleanup"; - public CloseEvent(UI source) { + public CleanupEvent(UI source) { super(source); } @@ -425,23 +426,23 @@ public abstract class UI extends AbstractComponentContainer implements } /** - * Interface for listening {@link UI.CloseEvent UI close events}. + * Interface for listening {@link UI.CleanupEvent UI cleanup events}. * */ - public interface CloseListener extends EventListener { + public interface CleanupListener extends EventListener { - public static final Method closeMethod = ReflectTools.findMethod( - CloseListener.class, "click", CloseEvent.class); + public static final Method cleanupMethod = ReflectTools.findMethod( + CleanupListener.class, "cleanup", CleanupEvent.class); /** - * Called when a CloseListener is notified of a CloseEvent. + * Called when a CleanupListener is notified of a CleanupEvent. * {@link UI#getCurrent()} returns <code>event.getUI()</code> within * this method. * * @param event * The close event that was fired. */ - public void close(CloseEvent event); + public void cleanup(CleanupEvent event); } /** @@ -654,10 +655,10 @@ public abstract class UI extends AbstractComponentContainer implements /** * For internal use only. */ - public void fireCloseEvent() { + public void fireCleanupEvent() { UI current = UI.getCurrent(); UI.setCurrent(this); - fireEvent(new CloseEvent(this)); + fireEvent(new CleanupEvent(this)); UI.setCurrent(current); } @@ -845,6 +846,8 @@ public abstract class UI extends AbstractComponentContainer implements private String theme; + private Navigator navigator; + /** * This method is used by Component.Focusable objects to request focus to * themselves. Focus renders must be handled at window level (instead of @@ -1126,9 +1129,9 @@ public abstract class UI extends AbstractComponentContainer implements * @param listener * The CloseListener that should be added. */ - public void addCloseListener(CloseListener listener) { - addListener(CloseEvent.CLOSE_EVENT_IDENTIFIER, CloseEvent.class, - listener, CloseListener.closeMethod); + public void addCleanupListener(CleanupListener listener) { + addListener(CleanupEvent.CLEANUP_EVENT_IDENTIFIER, CleanupEvent.class, + listener, CleanupListener.cleanupMethod); } /** @@ -1154,14 +1157,14 @@ public abstract class UI extends AbstractComponentContainer implements /** * Removes a close listener from the UI, if previously added with - * {@link #addCloseListener(CloseListener)}. + * {@link #addCleanupListener(CleanupListener)}. * * @param listener * The CloseListener that should be removed */ - public void removeCloseListener(CloseListener listener) { - removeListener(CloseEvent.CLOSE_EVENT_IDENTIFIER, CloseEvent.class, - listener); + public void removeCleanupListener(CleanupListener listener) { + removeListener(CleanupEvent.CLEANUP_EVENT_IDENTIFIER, + CleanupEvent.class, listener); } /** @@ -1188,6 +1191,25 @@ public abstract class UI extends AbstractComponentContainer implements } /** + * Returns the navigator attached to this UI or null if there is no + * navigator. + * + * @return + */ + public Navigator getNavigator() { + return navigator; + } + + /** + * For internal use only. + * + * @param navigator + */ + public void setNavigator(Navigator navigator) { + this.navigator = navigator; + } + + /** * Setting the caption of a UI is not supported. To set the title of the * HTML page, use Page.setTitle * @@ -1362,7 +1384,7 @@ public abstract class UI extends AbstractComponentContainer implements * heartbeat for this UI. * * @see #heartbeat() - * @see VaadinSession#closeInactiveUIs() + * @see VaadinSession#cleanupInactiveUIs() * * @return The time the last heartbeat request occurred. */ |