You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

application-lifecycle.asciidoc 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. ---
  2. title: Application Lifecycle
  3. order: 8
  4. layout: page
  5. ---
  6. [[application.lifecycle]]
  7. = Application Lifecycle
  8. In this section, we look into more technical details of application deployment,
  9. user sessions, and UI instance lifecycle. These details are not generally needed
  10. for writing Vaadin applications, but may be useful for understanding how they
  11. actually work and, especially, in what circumstances their execution ends.
  12. [[application.lifecycle.deployment]]
  13. == Deployment
  14. Before a Vaadin application can be used, it has to be deployed to a Java web
  15. server, as described in
  16. <<application-environment#application.environment,"Deploying
  17. an Application">>. Deploying reads the servlet classes annotated with the
  18. [literal]#++@WebServlet++# annotation or the [filename]#web.xml#
  19. deployment descriptor in the application to register servlets for
  20. specific URL paths and loads the classes. Deployment does not yet normally run
  21. any code in the application, although static blocks in classes are executed when
  22. they are loaded.
  23. [[application.lifecycle.deployment.redeployment]]
  24. === Undeploying and Redeploying
  25. Applications are undeployed when the server shuts down, during redeployment, and
  26. when they are explicitly undeployed. Undeploying a server-side Vaadin
  27. application ends its execution, all application classes are unloaded, and the
  28. heap space allocated by the application is freed for garbage-collection.
  29. If any user sessions are open at this point, the client-side state of the UIs is
  30. left hanging and an Out of Sync error is displayed on the next server request.
  31. [[application.lifecycle.deployment.serialization]]
  32. === Redeployment and Serialization
  33. Some servers, such as Tomcat, support __hot deployment__, where the classes are
  34. reloaded while preserving the memory state of the application. This is done by
  35. serializing the application state and then deserializing it after the classes
  36. are reloaded. This is, in fact, done with the basic Eclipse setup with Tomcat
  37. and if a UI is marked as [classname]#@PreserveOnRefresh#, you may actually need
  38. to give the [literal]#++?restartApplication++# URL parameter to force it to
  39. restart when you reload the page. Tools such as JRebel go even further by
  40. reloading the code in place without need for serialization. The server can also
  41. serialize the application state when shutting down and restarting, thereby
  42. preserving sessions over restarts.
  43. Serialization requires that the applications are __serializable__, that is, all
  44. classes implement the [interfacename]#Serializable# interface. All Vaadin
  45. classes do. If you extend them or implement interfaces, you can provide an
  46. optional serialization key, which is automatically generated by Eclipse if you
  47. use it. Serialization is also used for clustering and cloud computing.
  48. [[application.lifecycle.servlet-service]]
  49. == Vaadin Servlet, Portlet, and Service
  50. The [classname]#VaadinServlet#, or [classname]#VaadinPortlet# in a portal,
  51. receives all server requests mapped to it by its URL, as defined in the
  52. deployment configuration, and associates them with sessions. The sessions
  53. further associate the requests with particular UIs.
  54. When servicing requests, the Vaadin servlet or portlet handles all tasks common
  55. to both servlets and portlets in a [classname]#VaadinService#. It manages
  56. sessions, gives access to the deployment configuration information, handles
  57. system messages, and does various other tasks. Any further servlet or portlet
  58. specific tasks are handled in the corresponding
  59. [classname]#VaadinServletService# or [classname]#VaadinPortletService#. The
  60. service acts as the primary low-level customization layer for processing
  61. requests.
  62. [[application.lifecycle.servlet-service.servletcustomization]]
  63. === Customizing Vaadin Servlet
  64. Many common configuration tasks need to be done in the servlet class, which you
  65. already have if you are using the [literal]#++@WebServlet++# annotation for
  66. Servlet 3.0 to deploy the application. You can handle most customization by
  67. overriding the [methodname]#servletInitialized()# method, where the
  68. [classname]#VaadinService# object is available with [methodname]#getService()#
  69. (it would not be available in a constructor). You should always call
  70. [methodname]#super.servletInitialized()# in the beginning.
  71. [source, java]
  72. ----
  73. public class MyServlet extends VaadinServlet {
  74. @Override
  75. protected void servletInitialized()
  76. throws ServletException {
  77. super.servletInitialized();
  78. ...
  79. }
  80. }
  81. ----
  82. To add custom functionality around request handling, you can override the
  83. [methodname]#service()# method.
  84. [[application.lifecycle.servlet-service.servicecustomization]]
  85. === Customizing Vaadin Service
  86. To customize [classname]#VaadinService#, you first need to extend the
  87. [classname]#VaadinServlet# or - [classname]#Portlet# class and override the
  88. [methodname]#createServletService()# to create a custom service object.
  89. [[application.lifecycle.session]]
  90. == User Session
  91. ((("session")))
  92. A user session begins when a user first makes a request to a Vaadin servlet or
  93. portlet by opening the URL for a particular [classname]#UI#. All server requests
  94. belonging to a particular UI class are processed by the
  95. [classname]#VaadinServlet# or [classname]#VaadinPortlet# class. When a new
  96. client connects, it creates a new user session, represented by an instance of
  97. [classname]#VaadinSession#. Sessions are tracked using cookies stored in the
  98. browser.
  99. You can obtain the [classname]#VaadinSession# of a [classname]#UI# with
  100. [methodname]#getSession()# or globally with
  101. [methodname]#VaadinSession.getCurrent()#. It also provides access to the
  102. lower-level session objects, [interfacename]#HttpSession# and
  103. [interfacename]#PortletSession#, through a [classname]#WrappedSession#. You can
  104. also access the deployment configuration through [classname]#VaadinSession#, as
  105. described in
  106. <<application-environment#application.environment.configuration,"Deployment
  107. Configuration">>.
  108. A session ends after the last [classname]#UI# instance expires or is closed, as
  109. described later.
  110. [[application.lifecycle.session.init]]
  111. === Handling Session Initialization and Destruction
  112. ((("[classname]#SessionInitListener#")))
  113. ((("[classname]#SessionDestroyListener#")))
  114. ((("[classname]#VaadinService#")))
  115. You can handle session initialization and destruction by implementing a
  116. [interfacename]#SessionInitListener# or [interfacename]#SessionDestroyListener#,
  117. respectively, to the [classname]#VaadinService#.
  118. ((("[methodname]#servletInitialized()#")))
  119. ((("[classname]#VaadinServlet#")))
  120. You can do that best by extending [classname]#VaadinServlet# and overriding the
  121. [methodname]#servletInitialized()# method, as outlined in
  122. <<application.lifecycle.servlet-service>>.
  123. [source, java]
  124. ----
  125. public class MyServlet extends VaadinServlet
  126. implements SessionInitListener, SessionDestroyListener {
  127. @Override
  128. protected void servletInitialized() throws ServletException {
  129. super.servletInitialized();
  130. getService().addSessionInitListener(this);
  131. getService().addSessionDestroyListener(this);
  132. }
  133. @Override
  134. public void sessionInit(SessionInitEvent event)
  135. throws ServiceException {
  136. // Do session start stuff here
  137. }
  138. @Override
  139. public void sessionDestroy(SessionDestroyEvent event) {
  140. // Do session end stuff here
  141. }
  142. }
  143. ----
  144. [[application.lifecycle.ui]]
  145. == Loading a UI
  146. ((("UI", "loading")))
  147. When a browser first accesses a URL mapped to the servlet of a particular UI
  148. class, the Vaadin servlet generates a loader page. The page loads the
  149. client-side engine (widget set), which in turn loads the UI in a separate
  150. request to the Vaadin servlet.
  151. ((("[classname]#UIProvider#")))
  152. ((("[classname]#DefaultUIProvider#")))
  153. ((("[classname]#BrowserWindowOpener#")))
  154. A [classname]#UI# instance is created when the client-side engine makes its
  155. first request. The servlet creates the UIs using a [classname]#UIProvider#
  156. registered in the [classname]#VaadinSession# instance. A session has at least a
  157. [classname]#DefaultUIProvider# for managing UIs opened by the user. If the
  158. application lets the user open popup windows with a
  159. [classname]#BrowserWindowOpener#, each of them has a dedicated special UI
  160. provider.
  161. ((("[classname]#VaadinRequest#")))
  162. ((("[methodname]#init()#")))
  163. Once a new UI is created, its [methodname]#init()# method is called. The method
  164. gets the request as a [classname]#VaadinRequest#.
  165. [[application.lifecycle.ui.loaderpage]]
  166. === Customizing the Loader Page
  167. The HTML content of the loader page is generated as an HTML DOM object, which
  168. can be customized by implementing a [interfacename]#BootstrapListener# that
  169. modifies the DOM object. To do so, you need to extend the
  170. [classname]#VaadinServlet# and add a [interfacename]#SessionInitListener# to the
  171. service object, as outlined in <<application.lifecycle.session>>. You can then
  172. add the bootstrap listener to a session with
  173. [methodname]#addBootstrapListener()# when the session is initialized.
  174. Loading the widget set is handled in the loader page with functions defined in a
  175. separate [filename]#vaadinBootstrap.js# script.
  176. You can also use entirely custom loader code, such as in a static HTML page, as
  177. described in
  178. <<../advanced/advanced-embedding#advanced.embedding,"Embedding
  179. UIs in Web Pages">>.
  180. [[application.lifecycle.ui.uiprovider]]
  181. === Custom UI Providers
  182. ((("[interfacename]#UIProvider#", "custom")))
  183. You can create UI objects dynamically according to their request parameters,
  184. such as the URL path, by defining a custom [interfacename]#UIProvider#. You need
  185. to add custom UI providers to the session object which calls them. The providers
  186. are chained so that they are requested starting from the one added last, until
  187. one returns a UI (otherwise they return null). You can add a UI provider to a
  188. session most conveniently by implementing a custom servlet and adding the UI
  189. provider to sessions in a [interfacename]#SessionInitListener#.
  190. [[application.lifecycle.ui.preserving]]
  191. === Preserving UI on Refresh
  192. ((("UI", "preserving on refresh")))
  193. ((("[classname]#@PreserveOnRefresh#")))
  194. Reloading a page in the browser normally spawns a new [classname]#UI# instance
  195. and the old UI is left hanging, until cleaned up after a while. This can be
  196. undesired as it resets the UI state for the user. To preserve the UI, you can
  197. use the [classname]#@PreserveOnRefresh# annotation for the UI class. You can
  198. also use a [classname]#UIProvider# with a custom implementation of
  199. [methodname]#isUiPreserved()#.
  200. [source, java]
  201. ----
  202. @PreserveOnRefresh
  203. public class MyUI extends UI {
  204. ----
  205. Adding the ?restartApplication parameter in the URL tells the Vaadin servlet to
  206. create a new [classname]#UI# instance when loading the page, thereby overriding
  207. the [classname]#@PreserveOnRefresh#. This is often necessary when developing
  208. such a UI in Eclipse, when you need to restart it after redeploying, because
  209. Eclipse likes to persist the application state between redeployments. If you
  210. also include a URI fragment, the parameter should be given before the fragment.
  211. [[application.lifecycle.ui-expiration]]
  212. == UI Expiration
  213. ((("UI", "expiration")))
  214. [classname]#UI# instances are cleaned up if no communication is received from
  215. them after some time. If no other server requests are made, the client-side
  216. sends keep-alive heartbeat requests. A UI is kept alive for as long as requests
  217. or heartbeats are received from it. It expires if three consecutive heartbeats
  218. are missed.
  219. The heartbeats occur at an interval of 5 minutes, which can be changed with the
  220. [parameter]#heartbeatInterval# parameter of the servlet. You can configure the
  221. parameter in [classname]#@VaadinServletConfiguration# or in [filename]#web.xml#
  222. as described in
  223. <<application-environment#application.environment.parameters,"Other
  224. Servlet Configuration Parameters">>.
  225. When the UI cleanup happens, a [classname]#DetachEvent# is sent to all
  226. [classname]#DetachListener#s added to the UI. When the [classname]#UI# is
  227. detached from the session, [methodname]#detach()# is called for it.
  228. [[application.lifecycle.ui-closing]]
  229. == Closing UIs Explicitly
  230. ((("UI", "closing")))
  231. ((("[methodname]#close()#",
  232. "UI")))
  233. You can explicitly close a UI with [methodname]#close()#. The method marks the
  234. UI to be detached from the session after processing the current request.
  235. Therefore, the method does not invalidate the UI instance immediately and the
  236. response is sent as usual.
  237. Detaching a UI does not close the page or browser window in which the UI is
  238. running and further server request will cause error. Typically, you either want
  239. to close the window, reload it, or redirect it to another URL. If the page is a
  240. regular browser window or tab, browsers generally do not allow closing them
  241. programmatically, but redirection is possible. You can redirect the window to
  242. another URL with [methodname]#setLocation()#, as is done in the examples in
  243. <<application.lifecycle.session-closing>>. You can close popup windows by making
  244. JavaScript [methodname]#close()# call for them, as described in
  245. <<../advanced/advanced-windows#advanced.windows.popup-closing,"Closing
  246. Popup Windows">>.
  247. If you close other UI than the one associated with the current request, they
  248. will not be detached at the end of the current request, but after next request
  249. from the particular UI. You can make that occur quicker by making the UI
  250. heartbeat faster or immediately by using server push.
  251. [[application.lifecycle.session-expiration]]
  252. == Session Expiration
  253. ((("session", "expiration")))
  254. A session is kept alive by server requests caused by user interaction with the
  255. application as well as the heartbeat monitoring of the UIs. Once all UIs have
  256. expired, the session still remains. It is cleaned up from the server when the
  257. session timeout configured in the web application expires.
  258. ((("closeIdleSessions")))
  259. If there are active UIs in an application, their heartbeat keeps the session
  260. alive indefinitely. You may want to have the sessions timeout if the user is
  261. inactive long enough, which is the original purpose of the session timeout
  262. setting. ((("session",
  263. "timeout")))
  264. ((("closeIdleSessions")))
  265. If the [parameter]#closeIdleSessions# parameter of the servlet is set to
  266. [literal]#++true++# in the [filename]#web.xml#, as described in
  267. <<application-environment#application.environment.web-xml,"Using
  268. a web.xml Deployment Descriptor">>, the session and all of its UIs are closed
  269. when the timeout specified by the [parameter]#session-timeout# parameter of the
  270. servlet expires after the last non-heartbeat request. Once the session is gone,
  271. the browser will show an Out Of Sync error on the next server request.
  272. ((("redirection")))
  273. To avoid the ugly message, you may want to set a redirect URL for the UIs, as described in
  274. <<application-errors#application.errors.systemmessages,"Customizing
  275. System
  276. Messages">>.
  277. The related configuration parameters are described in
  278. <<application-environment#application.environment.parameters,"Other
  279. Servlet Configuration Parameters">>.
  280. ((("[interfacename]#SessionDestroyListener#")))
  281. You can handle session expiration on the server-side with a
  282. [interfacename]#SessionDestroyListener#, as described in
  283. <<application.lifecycle.session>>.
  284. [[application.lifecycle.session-closing]]
  285. == Closing a Session
  286. ((("session", "closing")))
  287. ((("[methodname]#close()#")))
  288. You can close a session by calling [methodname]#close()# on the
  289. [classname]#VaadinSession#. It is typically used when logging a user out and the
  290. session and all the UIs belonging to the session should be closed. The session
  291. is closed immediately and any objects related to it are not available after
  292. calling the method.
  293. When closing the session from a UI, you typically want to redirect the user to
  294. another URL.
  295. ((("redirection")))
  296. ((("[methodname]#setLocation()#")))
  297. ((("Page",
  298. "[methodname]#setLocation()#")))
  299. You can do the redirect using the [methodname]#setLocation()# method in
  300. [classname]#Page#. This needs to be done before closing the session, as the UI
  301. or page are not available after that. In the following example, we display a
  302. logout button, which closes the user session.
  303. ((("logout")))
  304. [source, java]
  305. ----
  306. public class MyUI extends UI {
  307. @Override
  308. protected void init(VaadinRequest request) {
  309. setContent(new Button("Logout", event -> {
  310. // Redirect this page immediately
  311. getPage().setLocation("/myapp/logout.html");
  312. // Close the session
  313. getSession().close();
  314. }));
  315. // Notice quickly if other UIs are closed
  316. setPollInterval(3000);
  317. }
  318. }
  319. ----
  320. This is not enough. When a session is closed from one UI, any other UIs attached
  321. to it are left hanging. When the client-side engine notices that a UI and the
  322. session are gone on the server-side, it displays a "Session Expired" message
  323. and, by default, reloads the UI when the message is clicked.
  324. ((("session", "expiration")))
  325. ((("redirection")))
  326. ((("system messages")))
  327. You can customize the message and the redirect URL in the system messages.
  328. It is described in <<application-errors#application.errors.systemmessages,"Customizing System Messages">>.
  329. ((("heartbeat")))
  330. ((("UI", "heartbeat")))
  331. ((("push")))
  332. ((("server push")))
  333. The client-side engine notices the expiration when user interaction causes a
  334. server request to be made or when the keep-alive heartbeat occurs. To make the
  335. UIs detect the situation faster, you need to make the heart beat faster, as was
  336. done in the example above. You can also use server push to close the other UIs
  337. immediately, as is done in the following example. Access to the UIs must be
  338. synchronized as described in
  339. <<../advanced/advanced-push#advanced.push,"Server Push">>.
  340. [source, java]
  341. ----
  342. @Push
  343. public class MyPushyUI extends UI {
  344. @Override
  345. protected void init(VaadinRequest request) {
  346. setContent(new Button("Logout", event -> {
  347. for (UI ui: VaadinSession.getCurrent().getUIs())
  348. ui.access(() -> {
  349. // Redirect from the page
  350. ui.getPage().setLocation("/logout.html");
  351. });
  352. getSession().close();
  353. }));
  354. }
  355. }
  356. ----
  357. In the above example, we assume that all UIs in the session have push enabled
  358. and that they should be redirected; popups you might want to close instead of
  359. redirecting. It is not necessary to call [methodname]#close()# for them
  360. individually, as we close the entire session afterwards.