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.

VaadinService.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /*
  2. * Copyright 2011 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.server;
  17. import java.io.File;
  18. import java.io.Serializable;
  19. import java.lang.reflect.Constructor;
  20. import java.lang.reflect.Method;
  21. import java.net.MalformedURLException;
  22. import java.net.URL;
  23. import java.util.ArrayList;
  24. import java.util.HashMap;
  25. import java.util.Locale;
  26. import javax.portlet.PortletContext;
  27. import javax.servlet.ServletContext;
  28. import javax.servlet.ServletException;
  29. import com.vaadin.annotations.PreserveOnRefresh;
  30. import com.vaadin.event.EventRouter;
  31. import com.vaadin.shared.ui.ui.UIConstants;
  32. import com.vaadin.ui.UI;
  33. import com.vaadin.util.CurrentInstance;
  34. import com.vaadin.util.ReflectTools;
  35. /**
  36. * Provide deployment specific settings that are required outside terminal
  37. * specific code.
  38. *
  39. * @author Vaadin Ltd.
  40. *
  41. * @since 7.0
  42. */
  43. public abstract class VaadinService implements Serializable {
  44. private static final String REINITIALIZING_SESSION_MARKER = VaadinService.class
  45. .getName() + ".reinitializing";
  46. private static final Method SESSION_INIT_METHOD = ReflectTools.findMethod(
  47. SessionInitListener.class, "sessionInit", SessionInitEvent.class);
  48. private static final Method SESSION_DESTROY_METHOD = ReflectTools
  49. .findMethod(SessionDestroyListener.class, "sessionDestroy",
  50. SessionDestroyEvent.class);
  51. /**
  52. * @deprecated As of 7.0. Only supported for {@link LegacyApplication}.
  53. */
  54. @Deprecated
  55. public static final String URL_PARAMETER_RESTART_APPLICATION = "restartApplication";
  56. /**
  57. * @deprecated As of 7.0. Only supported for {@link LegacyApplication}.
  58. */
  59. @Deprecated
  60. public static final String URL_PARAMETER_CLOSE_APPLICATION = "closeApplication";
  61. private final DeploymentConfiguration deploymentConfiguration;
  62. private final EventRouter eventRouter = new EventRouter();
  63. private SystemMessagesProvider systemMessagesProvider = DefaultSystemMessagesProvider
  64. .get();
  65. /**
  66. * Creates a new vaadin service based on a deployment configuration
  67. *
  68. * @param deploymentConfiguration
  69. * the deployment configuration for the service
  70. */
  71. public VaadinService(DeploymentConfiguration deploymentConfiguration) {
  72. this.deploymentConfiguration = deploymentConfiguration;
  73. }
  74. /**
  75. * Return the URL from where static files, e.g. the widgetset and the theme,
  76. * are served. In a standard configuration the VAADIN folder inside the
  77. * returned folder is what is used for widgetsets and themes.
  78. *
  79. * The returned folder is usually the same as the context path and
  80. * independent of e.g. the servlet mapping.
  81. *
  82. * @param request
  83. * the request for which the location should be determined
  84. *
  85. * @return The location of static resources (should contain the VAADIN
  86. * directory). Never ends with a slash (/).
  87. */
  88. public abstract String getStaticFileLocation(VaadinRequest request);
  89. /**
  90. * Gets the widgetset that is configured for this deployment, e.g. from a
  91. * parameter in web.xml.
  92. *
  93. * @param request
  94. * the request for which a widgetset is required
  95. * @return the name of the widgetset
  96. */
  97. public abstract String getConfiguredWidgetset(VaadinRequest request);
  98. /**
  99. * Gets the theme that is configured for this deployment, e.g. from a portal
  100. * parameter or just some sensible default value.
  101. *
  102. * @param request
  103. * the request for which a theme is required
  104. * @return the name of the theme
  105. */
  106. public abstract String getConfiguredTheme(VaadinRequest request);
  107. /**
  108. * Checks whether the UI will be rendered on its own in the browser or
  109. * whether it will be included into some other context. A standalone UI may
  110. * do things that might interfere with other parts of a page, e.g. changing
  111. * the page title and requesting focus upon loading.
  112. *
  113. * @param request
  114. * the request for which the UI is loaded
  115. * @return a boolean indicating whether the UI should be standalone
  116. */
  117. public abstract boolean isStandalone(VaadinRequest request);
  118. /**
  119. * Get the class loader to use for loading classes loaded by name, e.g.
  120. * custom UI classes. <code>null</code> indicates that the default class
  121. * loader should be used.
  122. *
  123. * @return the class loader to use, or <code>null</code>
  124. */
  125. public ClassLoader getClassLoader() {
  126. final String classLoaderName = getDeploymentConfiguration()
  127. .getApplicationOrSystemProperty("ClassLoader", null);
  128. ClassLoader classLoader;
  129. if (classLoaderName == null) {
  130. classLoader = getClass().getClassLoader();
  131. } else {
  132. try {
  133. final Class<?> classLoaderClass = getClass().getClassLoader()
  134. .loadClass(classLoaderName);
  135. final Constructor<?> c = classLoaderClass
  136. .getConstructor(new Class[] { ClassLoader.class });
  137. classLoader = (ClassLoader) c
  138. .newInstance(new Object[] { getClass().getClassLoader() });
  139. } catch (final Exception e) {
  140. throw new RuntimeException(
  141. "Could not find specified class loader: "
  142. + classLoaderName, e);
  143. }
  144. }
  145. return classLoader;
  146. }
  147. /**
  148. * Returns the MIME type of the specified file, or null if the MIME type is
  149. * not known. The MIME type is determined by the configuration of the
  150. * container, and may be specified in a deployment descriptor. Common MIME
  151. * types are "text/html" and "image/gif".
  152. *
  153. * @param resourceName
  154. * a String specifying the name of a file
  155. * @return a String specifying the file's MIME type
  156. *
  157. * @see ServletContext#getMimeType(String)
  158. * @see PortletContext#getMimeType(String)
  159. */
  160. public abstract String getMimeType(String resourceName);
  161. /**
  162. * Gets the deployment configuration.
  163. *
  164. * @return the deployment configuration
  165. */
  166. public DeploymentConfiguration getDeploymentConfiguration() {
  167. return deploymentConfiguration;
  168. }
  169. /**
  170. * Sets the system messages provider to use for getting system messages to
  171. * display to users of this service.
  172. *
  173. * @see #getSystemMessagesProvider()
  174. *
  175. * @param systemMessagesProvider
  176. * the system messages provider; <code>null</code> is not
  177. * allowed.
  178. */
  179. public void setSystemMessagesProvider(
  180. SystemMessagesProvider systemMessagesProvider) {
  181. if (systemMessagesProvider == null) {
  182. throw new IllegalArgumentException(
  183. "SystemMessagesProvider can not be null.");
  184. }
  185. this.systemMessagesProvider = systemMessagesProvider;
  186. }
  187. /**
  188. * Gets the system messages provider currently defined for this service.
  189. * <p>
  190. * By default, the {@link DefaultSystemMessagesProvider} which always
  191. * provides the built-in default {@link SystemMessages} is used.
  192. * </p>
  193. *
  194. * @see #setSystemMessagesProvider(SystemMessagesProvider)
  195. * @see SystemMessagesProvider
  196. * @see SystemMessages
  197. *
  198. * @return the system messages provider; not <code>null</code>
  199. */
  200. public SystemMessagesProvider getSystemMessagesProvider() {
  201. return systemMessagesProvider;
  202. }
  203. /**
  204. * Gets the system message to use for a specific locale. This method may
  205. * also be implemented to use information from current instances of various
  206. * objects, which means that this method might return different values for
  207. * the same locale under different circumstances.
  208. *
  209. * @param locale
  210. * the desired locale for the system messages
  211. * @param request
  212. * @return the system messages to use
  213. */
  214. public SystemMessages getSystemMessages(Locale locale, VaadinRequest request) {
  215. SystemMessagesInfo systemMessagesInfo = new SystemMessagesInfo();
  216. systemMessagesInfo.setLocale(locale);
  217. systemMessagesInfo.setService(this);
  218. systemMessagesInfo.setRequest(request);
  219. return getSystemMessagesProvider()
  220. .getSystemMessages(systemMessagesInfo);
  221. }
  222. /**
  223. * Returns the context base directory.
  224. *
  225. * Typically an application is deployed in a such way that is has an
  226. * application directory. For web applications this directory is the root
  227. * directory of the web applications. In some cases applications might not
  228. * have an application directory (for example web applications running
  229. * inside a war).
  230. *
  231. * @return The application base directory or null if the application has no
  232. * base directory.
  233. */
  234. public abstract File getBaseDirectory();
  235. /**
  236. * Adds a listener that gets notified when a new Vaadin service session is
  237. * initialized for this service.
  238. * <p>
  239. * Because of the way different service instances share the same session,
  240. * the listener is not necessarily notified immediately when the session is
  241. * created but only when the first request for that session is handled by
  242. * this service.
  243. *
  244. * @see #removeSessionInitListener(SessionInitListener)
  245. * @see SessionInitListener
  246. *
  247. * @param listener
  248. * the Vaadin service session initialization listener
  249. */
  250. public void addSessionInitListener(SessionInitListener listener) {
  251. eventRouter.addListener(SessionInitEvent.class, listener,
  252. SESSION_INIT_METHOD);
  253. }
  254. /**
  255. * Removes a Vaadin service session initialization listener from this
  256. * service.
  257. *
  258. * @see #addSessionInitListener(SessionInitListener)
  259. *
  260. * @param listener
  261. * the Vaadin service session initialization listener to remove.
  262. */
  263. public void removeSessionInitListener(SessionInitListener listener) {
  264. eventRouter.removeListener(SessionInitEvent.class, listener,
  265. SESSION_INIT_METHOD);
  266. }
  267. /**
  268. * Adds a listener that gets notified when a Vaadin service session that has
  269. * been initialized for this service is destroyed.
  270. *
  271. * @see #addSessionInitListener(SessionInitListener)
  272. *
  273. * @param listener
  274. * the vaadin service session destroy listener
  275. */
  276. public void addSessionDestroyListener(SessionDestroyListener listener) {
  277. eventRouter.addListener(SessionDestroyEvent.class, listener,
  278. SESSION_DESTROY_METHOD);
  279. }
  280. public void fireSessionDestroy(VaadinSession vaadinSession) {
  281. // Ignore if the session is being moved to a different backing session
  282. if (vaadinSession.getAttribute(REINITIALIZING_SESSION_MARKER) == Boolean.TRUE) {
  283. return;
  284. }
  285. for (UI ui : new ArrayList<UI>(vaadinSession.getUIs())) {
  286. vaadinSession.cleanupUI(ui);
  287. }
  288. eventRouter.fireEvent(new SessionDestroyEvent(this, vaadinSession));
  289. }
  290. /**
  291. * Removes a Vaadin service session destroy listener from this service.
  292. *
  293. * @see #addSessionDestroyListener(SessionDestroyListener)
  294. *
  295. * @param listener
  296. * the vaadin service session destroy listener
  297. */
  298. public void removeSessionDestroyListener(SessionDestroyListener listener) {
  299. eventRouter.removeListener(SessionDestroyEvent.class, listener,
  300. SESSION_DESTROY_METHOD);
  301. }
  302. /**
  303. * Attempts to find a Vaadin service session associated with this request.
  304. *
  305. * @param request
  306. * the request to get a vaadin service session for.
  307. *
  308. * @see VaadinSession
  309. *
  310. * @return the vaadin service session for the request, or <code>null</code>
  311. * if no session is found and this is a request for which a new
  312. * session shouldn't be created.
  313. */
  314. public VaadinSession findVaadinSession(VaadinRequest request)
  315. throws ServiceException, SessionExpiredException {
  316. VaadinSession vaadinSession = findOrCreateVaadinSession(request);
  317. if (vaadinSession == null) {
  318. return null;
  319. }
  320. VaadinSession.setCurrent(vaadinSession);
  321. request.setAttribute(VaadinSession.class.getName(), vaadinSession);
  322. return vaadinSession;
  323. }
  324. private VaadinSession findOrCreateVaadinSession(VaadinRequest request)
  325. throws SessionExpiredException, ServiceException {
  326. boolean requestCanCreateSession = requestCanCreateSession(request);
  327. /* Find an existing session for this request. */
  328. VaadinSession session = getExistingSession(request,
  329. requestCanCreateSession);
  330. if (session != null) {
  331. /*
  332. * There is an existing session. We can use this as long as the user
  333. * not specifically requested to close or restart it.
  334. */
  335. final boolean restartApplication = (request
  336. .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null);
  337. final boolean closeApplication = (request
  338. .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null);
  339. if (restartApplication) {
  340. closeSession(session, request.getWrappedSession(false));
  341. return createAndRegisterSession(request);
  342. } else if (closeApplication) {
  343. closeSession(session, request.getWrappedSession(false));
  344. return null;
  345. } else {
  346. return session;
  347. }
  348. }
  349. // No existing session was found
  350. if (requestCanCreateSession) {
  351. /*
  352. * If the request is such that it should create a new session if one
  353. * as not found, we do that.
  354. */
  355. return createAndRegisterSession(request);
  356. } else {
  357. /*
  358. * The session was not found and a new one should not be created.
  359. * Assume the session has expired.
  360. */
  361. throw new SessionExpiredException();
  362. }
  363. }
  364. private VaadinSession createAndRegisterSession(VaadinRequest request)
  365. throws ServiceException {
  366. VaadinSession session = createVaadinSession(request);
  367. VaadinSession.setCurrent(session);
  368. session.storeInSession(this, request.getWrappedSession());
  369. // Initial locale comes from the request
  370. Locale locale = request.getLocale();
  371. session.setLocale(locale);
  372. session.setConfiguration(getDeploymentConfiguration());
  373. session.setCommunicationManager(createCommunicationManager(session));
  374. ServletPortletHelper.initDefaultUIProvider(session, this);
  375. onVaadinSessionStarted(request, session);
  376. return session;
  377. }
  378. /**
  379. * Get the base URL that should be used for sending requests back to this
  380. * service.
  381. * <p>
  382. * This is only used to support legacy cases.
  383. *
  384. * @param request
  385. * @return
  386. * @throws MalformedURLException
  387. *
  388. * @deprecated As of 7.0. Only used to support {@link LegacyApplication}.
  389. */
  390. @Deprecated
  391. protected URL getApplicationUrl(VaadinRequest request)
  392. throws MalformedURLException {
  393. return null;
  394. }
  395. /**
  396. * Create a communication manager to use for the given service session.
  397. *
  398. * @param session
  399. * the service session for which a new communication manager is
  400. * needed
  401. * @return a new communication manager
  402. */
  403. protected abstract AbstractCommunicationManager createCommunicationManager(
  404. VaadinSession session);
  405. /**
  406. * Creates a new Vaadin service session.
  407. *
  408. * @param request
  409. * @return
  410. * @throws ServletException
  411. * @throws MalformedURLException
  412. */
  413. protected VaadinSession createVaadinSession(VaadinRequest request)
  414. throws ServiceException {
  415. return new VaadinSession(this);
  416. }
  417. private void onVaadinSessionStarted(VaadinRequest request,
  418. VaadinSession session) throws ServiceException {
  419. eventRouter.fireEvent(new SessionInitEvent(this, session, request));
  420. ServletPortletHelper.checkUiProviders(session, this);
  421. }
  422. private void closeSession(VaadinSession vaadinSession,
  423. WrappedSession session) {
  424. if (vaadinSession == null) {
  425. return;
  426. }
  427. if (session != null) {
  428. vaadinSession.removeFromSession(this);
  429. }
  430. }
  431. protected VaadinSession getExistingSession(VaadinRequest request,
  432. boolean allowSessionCreation) throws SessionExpiredException {
  433. // Ensures that the session is still valid
  434. final WrappedSession session = request
  435. .getWrappedSession(allowSessionCreation);
  436. if (session == null) {
  437. throw new SessionExpiredException();
  438. }
  439. VaadinSession vaadinSession = VaadinSession
  440. .getForSession(this, session);
  441. if (vaadinSession == null) {
  442. return null;
  443. }
  444. return vaadinSession;
  445. }
  446. /**
  447. * Checks whether it's valid to create a new service session as a result of
  448. * the given request.
  449. *
  450. * @param request
  451. * the request
  452. * @return <code>true</code> if it's valid to create a new service session
  453. * for the request; else <code>false</code>
  454. */
  455. protected abstract boolean requestCanCreateSession(VaadinRequest request);
  456. /**
  457. * Gets the currently used Vaadin service. The current service is
  458. * automatically defined when processing requests related to the service and
  459. * in threads started at a point when the current service is defined (see
  460. * {@link InheritableThreadLocal}). In other cases, (e.g. from background
  461. * threads started in some other way), the current service is not
  462. * automatically defined.
  463. *
  464. * @return the current Vaadin service instance if available, otherwise
  465. * <code>null</code>
  466. *
  467. * @see #setCurrentInstances(VaadinRequest, VaadinResponse)
  468. */
  469. public static VaadinService getCurrent() {
  470. return CurrentInstance.get(VaadinService.class);
  471. }
  472. /**
  473. * Sets the this Vaadin service as the current service and also sets the
  474. * current Vaadin request and Vaadin response. This method is used by the
  475. * framework to set the current instances when a request related to the
  476. * service is processed and they are cleared when the request has been
  477. * processed.
  478. * <p>
  479. * The application developer can also use this method to define the current
  480. * instances outside the normal request handling, e.g. when initiating
  481. * custom background threads.
  482. * </p>
  483. *
  484. * @param request
  485. * the Vaadin request to set as the current request, or
  486. * <code>null</code> if no request should be set.
  487. * @param response
  488. * the Vaadin response to set as the current response, or
  489. * <code>null</code> if no response should be set.
  490. *
  491. * @see #getCurrent()
  492. * @see #getCurrentRequest()
  493. * @see #getCurrentResponse()
  494. */
  495. public void setCurrentInstances(VaadinRequest request,
  496. VaadinResponse response) {
  497. CurrentInstance.setInheritable(VaadinService.class, this);
  498. CurrentInstance.set(VaadinRequest.class, request);
  499. CurrentInstance.set(VaadinResponse.class, response);
  500. }
  501. /**
  502. * Gets the currently processed Vaadin request. The current request is
  503. * automatically defined when the request is started. The current request
  504. * can not be used in e.g. background threads because of the way server
  505. * implementations reuse request instances.
  506. *
  507. * @return the current Vaadin request instance if available, otherwise
  508. * <code>null</code>
  509. *
  510. * @see #setCurrentInstances(VaadinRequest, VaadinResponse)
  511. */
  512. public static VaadinRequest getCurrentRequest() {
  513. return CurrentInstance.get(VaadinRequest.class);
  514. }
  515. /**
  516. * Gets the currently processed Vaadin request. The current request is
  517. * automatically defined when the request is started. The current request
  518. * can not be used in e.g. background threads because of the way server
  519. * implementations reuse request instances.
  520. *
  521. * @return the current Vaadin request instance if available, otherwise
  522. * <code>null</code>
  523. *
  524. * @see #setCurrentInstances(VaadinRequest, VaadinResponse)
  525. */
  526. public static VaadinResponse getCurrentResponse() {
  527. return CurrentInstance.get(VaadinResponse.class);
  528. }
  529. /**
  530. * Gets a unique name for this service. The name should be unique among
  531. * different services of the same type but the same for corresponding
  532. * instances running in different JVMs in a cluster. This is typically based
  533. * on e.g. the configured servlet's or portlet's name.
  534. *
  535. * @return the unique name of this service instance.
  536. */
  537. public abstract String getServiceName();
  538. /**
  539. * Finds the {@link UI} that belongs to the provided request. This is
  540. * generally only supported for UIDL requests as other request types are not
  541. * related to any particular UI or have the UI information encoded in a
  542. * non-standard way. The returned UI is also set as the current UI (
  543. * {@link UI#setCurrent(UI)}).
  544. *
  545. * @param request
  546. * the request for which a UI is desired
  547. * @return the UI belonging to the request
  548. *
  549. */
  550. public UI findUI(VaadinRequest request) {
  551. VaadinSession session = VaadinSession.getForSession(this,
  552. request.getWrappedSession());
  553. // Get UI id from the request
  554. String uiIdString = request.getParameter(UIConstants.UI_ID_PARAMETER);
  555. int uiId = Integer.parseInt(uiIdString);
  556. // Get lock before accessing data in session
  557. session.lock();
  558. try {
  559. UI ui = session.getUIById(uiId);
  560. UI.setCurrent(ui);
  561. return ui;
  562. } finally {
  563. session.unlock();
  564. }
  565. }
  566. /**
  567. * Check if the given UI should be associated with the
  568. * <code>window.name</code> so that it can be re-used if the browser window
  569. * is reloaded. This is typically determined by the UI provider which
  570. * typically checks the @{@link PreserveOnRefresh} annotation but UI
  571. * providers and ultimately VaadinService implementations may choose to
  572. * override the defaults.
  573. *
  574. * @param provider
  575. * the UI provider responsible for the UI
  576. * @param event
  577. * the UI create event with details about the UI
  578. *
  579. * @return <code>true</code> if the UI should be preserved on refresh;
  580. * <code>false</code> if a new UI instance should be initialized on
  581. * refreshed.
  582. */
  583. public boolean preserveUIOnRefresh(UIProvider provider, UICreateEvent event) {
  584. return provider.isPreservedOnRefresh(event);
  585. }
  586. /**
  587. * Discards the current session and creates a new session with the same
  588. * contents. The purpose of this is to introduce a new session key in order
  589. * to avoid session fixation attacks.
  590. * <p>
  591. * Please note that this method makes certain assumptions about how data is
  592. * stored in the underlying session and may thus not be compatible with some
  593. * environments.
  594. *
  595. * @param request
  596. * The Vaadin request for which the session should be
  597. * reinitialized
  598. */
  599. public static void reinitializeSession(VaadinRequest request) {
  600. WrappedSession oldSession = request.getWrappedSession();
  601. // Stores all attributes (security key, reference to this context
  602. // instance) so they can be added to the new session
  603. HashMap<String, Object> attrs = new HashMap<String, Object>();
  604. for (String name : oldSession.getAttributeNames()) {
  605. Object value = oldSession.getAttribute(name);
  606. if (value instanceof VaadinSession) {
  607. // set flag to avoid cleanup
  608. VaadinSession serviceSession = (VaadinSession) value;
  609. serviceSession.setAttribute(REINITIALIZING_SESSION_MARKER,
  610. Boolean.TRUE);
  611. }
  612. attrs.put(name, value);
  613. }
  614. // Invalidate the current session
  615. oldSession.invalidate();
  616. // Create a new session
  617. WrappedSession newSession = request.getWrappedSession();
  618. // Restores all attributes (security key, reference to this context
  619. // instance)
  620. for (String name : attrs.keySet()) {
  621. Object value = attrs.get(name);
  622. newSession.setAttribute(name, value);
  623. // Ensure VaadinServiceSession knows where it's stored
  624. if (value instanceof VaadinSession) {
  625. VaadinSession serviceSession = (VaadinSession) value;
  626. serviceSession.storeInSession(serviceSession.getService(),
  627. newSession);
  628. serviceSession
  629. .setAttribute(REINITIALIZING_SESSION_MARKER, null);
  630. }
  631. }
  632. }
  633. /**
  634. * Creates and returns a unique ID for the DIV where the UI is to be
  635. * rendered.
  636. *
  637. * @param session
  638. * The service session to which the bootstrapped UI will belong.
  639. * @param request
  640. * The request for which a div id is needed
  641. * @param uiClass
  642. * The class of the UI that will be bootstrapped
  643. *
  644. * @return the id to use in the DOM
  645. */
  646. public abstract String getMainDivId(VaadinSession session,
  647. VaadinRequest request, Class<? extends UI> uiClass);
  648. /**
  649. * Closes the VaadinServiceSession and discards all associated UI state.
  650. * After the session has been discarded, any UIs that have been left open
  651. * will give an Out of sync error (
  652. * {@link SystemMessages#getOutOfSyncCaption()}) error and a new session
  653. * will be created for serving new UIs.
  654. * <p>
  655. * To avoid causing out of sync errors, you should typically redirect to
  656. * some other page using {@link Page#setLocation(String)} to make the
  657. * browser unload the invalidated UI.
  658. *
  659. * @param session
  660. * the session to close
  661. */
  662. public void closeSession(VaadinSession session) {
  663. session.removeFromSession(this);
  664. }
  665. }