diff options
Diffstat (limited to 'documentation/application/application-lifecycle.asciidoc')
-rw-r--r-- | documentation/application/application-lifecycle.asciidoc | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/documentation/application/application-lifecycle.asciidoc b/documentation/application/application-lifecycle.asciidoc new file mode 100644 index 0000000000..269f3d75b5 --- /dev/null +++ b/documentation/application/application-lifecycle.asciidoc @@ -0,0 +1,502 @@ +--- +title: Application Lifecycle +order: 8 +layout: page +--- + +[[application.lifecycle]] += Application Lifecycle + +In this section, we look into more technical details of application deployment, +user sessions, and UI instance lifecycle. These details are not generally needed +for writing Vaadin applications, but may be useful for understanding how they +actually work and, especially, in what circumstances their execution ends. + +[[application.lifecycle.deployment]] +== Deployment + +Before a Vaadin application can be used, it has to be deployed to a Java web +server, as described in +<<dummy/../../../framework/application/application-environment#application.environment,"Deploying +an Application">>. Deploying reads the servlet classes annotated with the +[literal]#++@WebServlet++# annotation (Servlet 3.0) or the [filename]#web.xml# +deployment descriptor (Servlet 2.4) in the application to register servlets for +specific URL paths and loads the classes. Deployment does not yet normally run +any code in the application, although static blocks in classes are executed when +they are loaded. + +[[application.lifecycle.deployment.redeployment]] +=== Undeploying and Redeploying + +Applications are undeployed when the server shuts down, during redeployment, and +when they are explicitly undeployed. Undeploying a server-side Vaadin +application ends its execution, all application classes are unloaded, and the +heap space allocated by the application is freed for garbage-collection. + +If any user sessions are open at this point, the client-side state of the UIs is +left hanging and an Out of Sync error is displayed on the next server request. + + +[[application.lifecycle.deployment.serialization]] +=== Redeployment and Serialization + +Some servers, such as Tomcat, support __hot deployment__, where the classes are +reloaded while preserving the memory state of the application. This is done by +serializing the application state and then deserializing it after the classes +are reloaded. This is, in fact, done with the basic Eclipse setup with Tomcat +and if a UI is marked as [classname]#@PreserveOnRefresh#, you may actually need +to give the [literal]#++?restartApplication++# URL parameter to force it to +restart when you reload the page. Tools such as JRebel go even further by +reloading the code in place without need for serialization. The server can also +serialize the application state when shutting down and restarting, thereby +preserving sessions over restarts. + +Serialization requires that the applications are __serializable__, that is, all +classes implement the [interfacename]#Serializable# interface. All Vaadin +classes do. If you extend them or implement interfaces, you can provide an +optional serialization key, which is automatically generated by Eclipse if you +use it. Serialization is also used for clustering and cloud computing, such as +with Google App Engine. + +ifdef::web[] +For more about that topic, see +<<dummy/../../../framework/advanced/advanced-gae#advanced.gae,"Google App Engine +Integration">>. +endif::web[] + + + +[[application.lifecycle.servlet-service]] +== Vaadin Servlet, Portlet, and Service + +The [classname]#VaadinServlet#, or [classname]#VaadinPortlet# in a portal, +receives all server requests mapped to it by its URL, as defined in the +deployment configuration, and associates them with sessions. The sessions +further associate the requests with particular UIs. + +When servicing requests, the Vaadin servlet or portlet handles all tasks common +to both servlets and portlets in a [classname]#VaadinService#. It manages +sessions, gives access to the deployment configuration information, handles +system messages, and does various other tasks. Any further servlet or portlet +specific tasks are handled in the corresponding +[classname]#VaadinServletService# or [classname]#VaadinPortletService#. The +service acts as the primary low-level customization layer for processing +requests. + +[[application.lifecycle.servlet-service.servletcustomization]] +=== Customizing Vaadin Servlet + +Many common configuration tasks need to be done in the servlet class, which you +already have if you are using the [literal]#++@WebServlet++# annotation for +Servlet 3.0 to deploy the application. You can handle most customization by +overriding the [methodname]#servletInitialized()# method, where the +[classname]#VaadinService# object is available with [methodname]#getService()# +(it would not be available in a constructor). You should always call +[methodname]#super.servletInitialized()# in the beginning. + + +[source, java] +---- +public class MyServlet extends VaadinServlet { + @Override + protected void servletInitialized() + throws ServletException { + super.servletInitialized(); + + ... + } +} +---- + +To add custom functionality around request handling, you can override the +[methodname]#service()# method. + +To use the custom servlet class in a Servlet 2.4 project, you need to define it +in the [filename]#web.xml# deployment descriptor instead of the regular +[classname]#VaadinServlet# class, as described in +<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using +a web.xml Deployment Descriptor">>. + + +ifdef::web[] +[[application.lifecycle.servlet-service.portletcustomization]] +=== Customizing Vaadin Portlet + +__To Be Done__ + +endif::web[] + +ifdef::web[] +[[application.lifecycle.servlet-service.servicecustomization]] +=== Customizing Vaadin Service + +To customize [classname]#VaadinService#, you first need to extend the +[classname]#VaadinServlet# or - [classname]#Portlet# class and override the +[methodname]#createServletService()# to create a custom service object. + +endif::web[] + + +[[application.lifecycle.session]] +== User Session + +((("session"))) +A user session begins when a user first makes a request to a Vaadin servlet or +portlet by opening the URL for a particular [classname]#UI#. All server requests +belonging to a particular UI class are processed by the +[classname]#VaadinServlet# or [classname]#VaadinPortlet# class. When a new +client connects, it creates a new user session, represented by an instance of +[classname]#VaadinSession#. Sessions are tracked using cookies stored in the +browser. + +You can obtain the [classname]#VaadinSession# of a [classname]#UI# with +[methodname]#getSession()# or globally with +[methodname]#VaadinSession.getCurrent()#. It also provides access to the +lower-level session objects, [interfacename]#HttpSession# and +[interfacename]#PortletSession#, through a [classname]#WrappedSession#. You can +also access the deployment configuration through [classname]#VaadinSession#, as +described in +<<dummy/../../../framework/application/application-environment#application.environment.configuration,"Deployment +Configuration">>. + +A session ends after the last [classname]#UI# instance expires or is closed, as +described later. + +[[application.lifecycle.session.init]] +=== Handling Session Initialization and Destruction + +((("[classname]#SessionInitListener#"))) +((("[classname]#SessionDestroyListener#"))) +((("[classname]#VaadinService#"))) +You can handle session initialization and destruction by implementing a +[interfacename]#SessionInitListener# or [interfacename]#SessionDestroyListener#, +respectively, to the [classname]#VaadinService#. +((("[methodname]#servletInitialized()#"))) +((("[classname]#VaadinServlet#"))) +You can do that best by extending [classname]#VaadinServlet# and overriding the +[methodname]#servletInitialized()# method, as outlined in +<<application.lifecycle.servlet-service>>. + + +[source, java] +---- +public class MyServlet extends VaadinServlet + implements SessionInitListener, SessionDestroyListener { + + @Override + protected void servletInitialized() throws ServletException { + super.servletInitialized(); + getService().addSessionInitListener(this); + getService().addSessionDestroyListener(this); + } + + @Override + public void sessionInit(SessionInitEvent event) + throws ServiceException { + // Do session start stuff here + } + + @Override + public void sessionDestroy(SessionDestroyEvent event) { + // Do session end stuff here + } +} +---- + +If using Servlet 2.4, you need to configure the custom servlet class in the +[parameter]#servlet-class# parameter in the [filename]#web.xml# descriptor +instead of the [classname]#VaadinServlet#, as described in +<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using +a web.xml Deployment Descriptor">>. + + + +[[application.lifecycle.ui]] +== Loading a UI + +((("UI", "loading"))) +When a browser first accesses a URL mapped to the servlet of a particular UI +class, the Vaadin servlet generates a loader page. The page loads the +client-side engine (widget set), which in turn loads the UI in a separate +request to the Vaadin servlet. + +((("[classname]#UIProvider#"))) +((("[classname]#DefaultUIProvider#"))) +((("[classname]#BrowserWindowOpener#"))) +A [classname]#UI# instance is created when the client-side engine makes its +first request. The servlet creates the UIs using a [classname]#UIProvider# +registered in the [classname]#VaadinSession# instance. A session has at least a +[classname]#DefaultUIProvider# for managing UIs opened by the user. If the +application lets the user open popup windows with a +[classname]#BrowserWindowOpener#, each of them has a dedicated special UI +provider. + +((("[classname]#VaadinRequest#"))) +((("[methodname]#init()#"))) +Once a new UI is created, its [methodname]#init()# method is called. The method +gets the request as a [classname]#VaadinRequest#. + +[[application.lifecycle.ui.loaderpage]] +=== Customizing the Loader Page + +The HTML content of the loader page is generated as an HTML DOM object, which +can be customized by implementing a [interfacename]#BootstrapListener# that +modifies the DOM object. To do so, you need to extend the +[classname]#VaadinServlet# and add a [interfacename]#SessionInitListener# to the +service object, as outlined in <<application.lifecycle.session>>. You can then +add the bootstrap listener to a session with +[methodname]#addBootstrapListener()# when the session is initialized. + +Loading the widget set is handled in the loader page with functions defined in a +separate [filename]#vaadinBootstrap.js# script. + +You can also use entirely custom loader code, such as in a static HTML page, as +described in +<<dummy/../../../framework/advanced/advanced-embedding#advanced.embedding,"Embedding +UIs in Web Pages">>. + + +[[application.lifecycle.ui.uiprovider]] +=== Custom UI Providers + +((("[interfacename]#UIProvider#", "custom"))) +You can create UI objects dynamically according to their request parameters, +such as the URL path, by defining a custom [interfacename]#UIProvider#. You need +to add custom UI providers to the session object which calls them. The providers +are chained so that they are requested starting from the one added last, until +one returns a UI (otherwise they return null). You can add a UI provider to a +session most conveniently by implementing a custom servlet and adding the UI +provider to sessions in a [interfacename]#SessionInitListener#. + +You can find an example of custom UI providers in +<<dummy/../../../mobile/mobile-features#mobile.features.fallback,"Providing a +Fallback UI">>. + + +[[application.lifecycle.ui.preserving]] +=== Preserving UI on Refresh + +((("UI", "preserving on refresh"))) +((("[classname]#@PreserveOnRefresh#"))) +Reloading a page in the browser normally spawns a new [classname]#UI# instance +and the old UI is left hanging, until cleaned up after a while. This can be +undesired as it resets the UI state for the user. To preserve the UI, you can +use the [classname]#@PreserveOnRefresh# annotation for the UI class. You can +also use a [classname]#UIProvider# with a custom implementation of +[methodname]#isUiPreserved()#. + + +[source, java] +---- +@PreserveOnRefresh +public class MyUI extends UI { +---- + +Adding the ?restartApplication parameter in the URL tells the Vaadin servlet to +create a new [classname]#UI# instance when loading the page, thereby overriding +the [classname]#@PreserveOnRefresh#. This is often necessary when developing +such a UI in Eclipse, when you need to restart it after redeploying, because +Eclipse likes to persist the application state between redeployments. If you +also include a URI fragment, the parameter should be given before the fragment. + + + +[[application.lifecycle.ui-expiration]] +== UI Expiration + +((("UI", "expiration"))) +[classname]#UI# instances are cleaned up if no communication is received from +them after some time. If no other server requests are made, the client-side +sends keep-alive heartbeat requests. A UI is kept alive for as long as requests +or heartbeats are received from it. It expires if three consecutive heartbeats +are missed. + +The heartbeats occur at an interval of 5 minutes, which can be changed with the +[parameter]#heartbeatInterval# parameter of the servlet. You can configure the +parameter in [classname]#@VaadinServletConfiguration# or in [filename]#web.xml# +as described in +<<dummy/../../../framework/application/application-environment#application.environment.parameters,"Other +Servlet Configuration Parameters">>. + +When the UI cleanup happens, a [classname]#DetachEvent# is sent to all +[classname]#DetachListener#s added to the UI. When the [classname]#UI# is +detached from the session, [methodname]#detach()# is called for it. + + +[[application.lifecycle.ui-closing]] +== Closing UIs Explicitly + +((("UI", "closing"))) +((("[methodname]#close()#", +"UI"))) +You can explicitly close a UI with [methodname]#close()#. The method marks the +UI to be detached from the session after processing the current request. +Therefore, the method does not invalidate the UI instance immediately and the +response is sent as usual. + +Detaching a UI does not close the page or browser window in which the UI is +running and further server request will cause error. Typically, you either want +to close the window, reload it, or redirect it to another URL. If the page is a +regular browser window or tab, browsers generally do not allow closing them +programmatically, but redirection is possible. You can redirect the window to +another URL with [methodname]#setLocation()#, as is done in the examples in +<<application.lifecycle.session-closing>>. You can close popup windows by making +JavaScript [methodname]#close()# call for them, as described in +<<dummy/../../../framework/advanced/advanced-windows#advanced.windows.popup-closing,"Closing +Popup Windows">>. + +If you close other UI than the one associated with the current request, they +will not be detached at the end of the current request, but after next request +from the particular UI. You can make that occur quicker by making the UI +heartbeat faster or immediately by using server push. + + +[[application.lifecycle.session-expiration]] +== Session Expiration + +((("session", "expiration"))) +A session is kept alive by server requests caused by user interaction with the +application as well as the heartbeat monitoring of the UIs. Once all UIs have +expired, the session still remains. It is cleaned up from the server when the +session timeout configured in the web application expires. + +((("closeIdleSessions"))) +If there are active UIs in an application, their heartbeat keeps the session +alive indefinitely. You may want to have the sessions timeout if the user is +inactive long enough, which is the original purpose of the session timeout +setting. ((("session", +"timeout"))) +((("closeIdleSessions"))) +If the [parameter]#closeIdleSessions# parameter of the servlet is set to +[literal]#++true++# in the [filename]#web.xml#, as described in +<<dummy/../../../framework/application/application-environment#application.environment.web-xml,"Using +a web.xml Deployment Descriptor">>, the session and all of its UIs are closed +when the timeout specified by the [parameter]#session-timeout# parameter of the +servlet expires after the last non-heartbeat request. Once the session is gone, +the browser will show an Out Of Sync error on the next server request. +((("redirection"))) +To avoid the ugly message, you may want to set a redirect URL for the UIs + +ifdef::web[] +, as described in +<<dummy/../../../framework/application/application-errors#application.errors.systemmessages,"Customizing +System +Messages">> +endif::web[] +. + +The related configuration parameters are described in +<<dummy/../../../framework/application/application-environment#application.environment.parameters,"Other +Servlet Configuration Parameters">>. + +((("[interfacename]#SessionDestroyListener#"))) +You can handle session expiration on the server-side with a +[interfacename]#SessionDestroyListener#, as described in +<<application.lifecycle.session>>. + + +[[application.lifecycle.session-closing]] +== Closing a Session + +((("session", "closing"))) +((("[methodname]#close()#"))) +You can close a session by calling [methodname]#close()# on the +[classname]#VaadinSession#. It is typically used when logging a user out and the +session and all the UIs belonging to the session should be closed. The session +is closed immediately and any objects related to it are not available after +calling the method. + +When closing the session from a UI, you typically want to redirect the user to +another URL. +((("redirection"))) +((("[methodname]#setLocation()#"))) +((("Page", +"[methodname]#setLocation()#"))) +You can do the redirect using the [methodname]#setLocation()# method in +[classname]#Page#. This needs to be done before closing the session, as the UI +or page are not available after that. In the following example, we display a +logout button, which closes the user session. + +((("logout"))) + +[source, java] +---- +public class MyUI extends UI { + @Override + protected void init(VaadinRequest request) { + setContent(new Button("Logout", event -> {// Java 8 + // Redirect this page immediately + getPage().setLocation("/myapp/logout.html"); + + // Close the session + getSession().close(); + })); + + // Notice quickly if other UIs are closed + setPollInterval(3000); + } +} +---- +See the http://demo.vaadin.com/book-examples-vaadin7/book#application.lifecycle.closing[on-line example, window="_blank"]. + +This is not enough. When a session is closed from one UI, any other UIs attached +to it are left hanging. When the client-side engine notices that a UI and the +session are gone on the server-side, it displays a "Session Expired" message +and, by default, reloads the UI when the message is clicked. ((("session", +"expiration"))) +((("redirection"))) +((("system +messages"))) +You can customize the message and the redirect URL in the system messages + +ifdef::web[] +, as described in +<<dummy/../../../framework/application/application-errors#application.errors.systemmessages,"Customizing +System +Messages">> +endif::web[] +. + +((("heartbeat"))) +((("UI", +"heartbeat"))) +((("push"))) +((("server +push"))) +The client-side engine notices the expiration when user interaction causes a +server request to be made or when the keep-alive heartbeat occurs. To make the +UIs detect the situation faster, you need to make the heart beat faster, as was +done in the example above. You can also use server push to close the other UIs +immediately, as is done in the following example. Access to the UIs must be +synchronized as described in +<<dummy/../../../framework/advanced/advanced-push#advanced.push,"Server Push">>. + + +[source, java] +---- +@Push +public class MyPushyUI extends UI { + @Override + protected void init(VaadinRequest request) { + setContent(new Button("Logout", event -> {// Java 8 + for (UI ui: VaadinSession.getCurrent().getUIs()) + ui.access(() -> { + // Redirect from the page + ui.getPage().setLocation("/logout.html"); + }); + + getSession().close(); + })); + } +} +---- +See the http://demo.vaadin.com/book-examples-vaadin7/book#application.lifecycle.closingall[on-line example, window="_blank"]. + +In the above example, we assume that all UIs in the session have push enabled +and that they should be redirected; popups you might want to close instead of +redirecting. It is not necessary to call [methodname]#close()# for them +individually, as we close the entire session afterwards. + + + + |