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

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