123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- ---
- 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
- <<application-environment#application.environment,"Deploying
- an Application">>. Deploying reads the servlet classes annotated with the
- [literal]#++@WebServlet++# annotation or the [filename]#web.xml#
- deployment descriptor 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.
-
-
- [[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.
-
-
- [[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.
-
-
- [[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
- <<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
- }
- }
- ----
-
-
- [[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
- <<../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#.
-
-
- [[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
- <<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
- <<../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
- <<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, as described in
- <<application-errors#application.errors.systemmessages,"Customizing
- System
- Messages">>.
-
- The related configuration parameters are described in
- <<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 -> {
- // Redirect this page immediately
- getPage().setLocation("/myapp/logout.html");
-
- // Close the session
- getSession().close();
- }));
-
- // Notice quickly if other UIs are closed
- setPollInterval(3000);
- }
- }
- ----
-
- 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.
-
- It is described in <<application-errors#application.errors.systemmessages,"Customizing System Messages">>.
-
- ((("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
- <<../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 -> {
- for (UI ui: VaadinSession.getCurrent().getUIs())
- ui.access(() -> {
- // Redirect from the page
- ui.getPage().setLocation("/logout.html");
- });
-
- getSession().close();
- }));
- }
- }
- ----
-
- 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.
|