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.

VaadinSession.java 49KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492
  1. /*
  2. * Copyright 2000-2016 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.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.io.Serializable;
  21. import java.lang.reflect.Method;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.Enumeration;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.LinkedList;
  28. import java.util.List;
  29. import java.util.Locale;
  30. import java.util.Map;
  31. import java.util.Queue;
  32. import java.util.Set;
  33. import java.util.UUID;
  34. import java.util.concurrent.ConcurrentLinkedQueue;
  35. import java.util.concurrent.ExecutionException;
  36. import java.util.concurrent.Future;
  37. import java.util.concurrent.FutureTask;
  38. import java.util.concurrent.locks.Lock;
  39. import java.util.concurrent.locks.ReentrantLock;
  40. import java.util.logging.Level;
  41. import java.util.logging.Logger;
  42. import javax.portlet.PortletSession;
  43. import javax.servlet.http.HttpSession;
  44. import javax.servlet.http.HttpSessionBindingEvent;
  45. import javax.servlet.http.HttpSessionBindingListener;
  46. import com.vaadin.event.EventRouter;
  47. import com.vaadin.shared.Registration;
  48. import com.vaadin.shared.communication.PushMode;
  49. import com.vaadin.ui.UI;
  50. import com.vaadin.util.CurrentInstance;
  51. import com.vaadin.util.ReflectTools;
  52. /**
  53. * Contains everything that Vaadin needs to store for a specific user. This is
  54. * typically stored in a {@link HttpSession} or {@link PortletSession}, but
  55. * others storage mechanisms might also be used.
  56. * <p>
  57. * Everything inside a {@link VaadinSession} should be serializable to ensure
  58. * compatibility with schemes using serialization for persisting the session
  59. * data.
  60. *
  61. * @author Vaadin Ltd
  62. * @since 7.0.0
  63. */
  64. @SuppressWarnings("serial")
  65. public class VaadinSession implements HttpSessionBindingListener, Serializable {
  66. /**
  67. * Encapsulates a {@link Runnable} submitted using
  68. * {@link VaadinSession#access(Runnable)}. This class is used internally by
  69. * the framework and is not intended to be directly used by application
  70. * developers.
  71. *
  72. * @since 7.1
  73. * @author Vaadin Ltd
  74. */
  75. public static class FutureAccess extends FutureTask<Void> {
  76. private final VaadinSession session;
  77. private final Runnable runnable;
  78. /**
  79. * Creates an instance for the given runnable
  80. *
  81. * @param session
  82. * the session to which the task belongs
  83. *
  84. * @param runnable
  85. * the runnable to run when this task is purged from the
  86. * queue
  87. */
  88. public FutureAccess(VaadinSession session, Runnable runnable) {
  89. super(runnable, null);
  90. this.session = session;
  91. this.runnable = runnable;
  92. }
  93. @Override
  94. public Void get() throws InterruptedException, ExecutionException {
  95. /*
  96. * Help the developer avoid programming patterns that cause
  97. * deadlocks unless implemented very carefully. get(long, TimeUnit)
  98. * does not have the same detection since a sensible timeout should
  99. * avoid completely locking up the application.
  100. *
  101. * Even though no deadlock could occur after the runnable has been
  102. * run, the check is always done as the deterministic behavior makes
  103. * it easier to detect potential problems.
  104. */
  105. VaadinService.verifyNoOtherSessionLocked(session);
  106. return super.get();
  107. }
  108. /**
  109. * Handles exceptions thrown during the execution of this task.
  110. *
  111. * @since 7.1.8
  112. * @param exception
  113. * the thrown exception.
  114. */
  115. public void handleError(Exception exception) {
  116. try {
  117. if (runnable instanceof ErrorHandlingRunnable) {
  118. ErrorHandlingRunnable errorHandlingRunnable = (ErrorHandlingRunnable) runnable;
  119. errorHandlingRunnable.handleError(exception);
  120. } else {
  121. ErrorEvent errorEvent = new ErrorEvent(exception);
  122. ErrorHandler errorHandler = ErrorEvent
  123. .findErrorHandler(session);
  124. if (errorHandler == null) {
  125. errorHandler = new DefaultErrorHandler();
  126. }
  127. errorHandler.error(errorEvent);
  128. }
  129. } catch (Exception e) {
  130. getLogger().log(Level.SEVERE, e.getMessage(), e);
  131. }
  132. }
  133. }
  134. /**
  135. * The lifecycle state of a VaadinSession.
  136. *
  137. * @since 7.2
  138. */
  139. public enum State {
  140. /**
  141. * The session is active and accepting client requests.
  142. */
  143. OPEN,
  144. /**
  145. * The {@link VaadinSession#close() close} method has been called; the
  146. * session will be closed as soon as the current request ends.
  147. */
  148. CLOSING,
  149. /**
  150. * The session is closed; all the {@link UI}s have been removed and
  151. * {@link SessionDestroyListener}s have been called.
  152. */
  153. CLOSED;
  154. private boolean isValidChange(State newState) {
  155. return (this == OPEN && newState == CLOSING)
  156. || (this == CLOSING && newState == CLOSED);
  157. }
  158. }
  159. /**
  160. * The name of the parameter that is by default used in e.g. web.xml to
  161. * define the name of the default {@link UI} class.
  162. */
  163. // javadoc in UI should be updated if this value is changed
  164. public static final String UI_PARAMETER = "UI";
  165. private static final Method BOOTSTRAP_FRAGMENT_METHOD = ReflectTools
  166. .findMethod(BootstrapListener.class, "modifyBootstrapFragment",
  167. BootstrapFragmentResponse.class);
  168. private static final Method BOOTSTRAP_PAGE_METHOD = ReflectTools.findMethod(
  169. BootstrapListener.class, "modifyBootstrapPage",
  170. BootstrapPageResponse.class);
  171. /**
  172. * Configuration for the session.
  173. */
  174. private DeploymentConfiguration configuration;
  175. /**
  176. * Default locale of the session.
  177. */
  178. private Locale locale;
  179. /**
  180. * Session wide error handler which is used by default if an error is left
  181. * unhandled.
  182. */
  183. private ErrorHandler errorHandler = new DefaultErrorHandler();
  184. /**
  185. * The converter factory that is used to provide default converters for the
  186. * session.
  187. */
  188. @Deprecated
  189. private Object converterFactory;
  190. private LinkedList<RequestHandler> requestHandlers = new LinkedList<>();
  191. private int nextUIId = 0;
  192. private Map<Integer, UI> uIs = new HashMap<>();
  193. private final Map<String, Integer> embedIdMap = new HashMap<>();
  194. private final EventRouter eventRouter = new EventRouter();
  195. private GlobalResourceHandler globalResourceHandler;
  196. protected WebBrowser browser = new WebBrowser();
  197. private DragAndDropService dragAndDropService;
  198. private LegacyCommunicationManager communicationManager;
  199. private long cumulativeRequestDuration = 0;
  200. private long lastRequestDuration = -1;
  201. private long lastRequestTimestamp = System.currentTimeMillis();
  202. private State state = State.OPEN;
  203. private transient WrappedSession session;
  204. private final Map<String, Object> attributes = new HashMap<>();
  205. private LinkedList<UIProvider> uiProviders = new LinkedList<>();
  206. private transient VaadinService service;
  207. private transient Lock lock;
  208. /*
  209. * Pending tasks can't be serialized and the queue should be empty when the
  210. * session is serialized as long as it doesn't happen while some other
  211. * thread has the lock.
  212. */
  213. private transient ConcurrentLinkedQueue<FutureAccess> pendingAccessQueue = new ConcurrentLinkedQueue<>();
  214. /**
  215. * Creates a new VaadinSession tied to a VaadinService.
  216. *
  217. * @param service
  218. * the Vaadin service for the new session
  219. */
  220. public VaadinSession(VaadinService service) {
  221. this.service = service;
  222. try {
  223. // This is to avoid having ConverterFactory/DefaultConverterFactory
  224. // in the server package
  225. Class<?> cls = getClass().getClassLoader().loadClass(
  226. "com.vaadin.v7.data.util.converter.DefaultConverterFactory");
  227. Object factory = cls.newInstance();
  228. converterFactory = factory;
  229. } catch (Exception e) {
  230. // DefaultConverterFactory not found, go on without and warn later
  231. // if it is used
  232. }
  233. }
  234. /**
  235. * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)
  236. */
  237. @Override
  238. public void valueBound(HttpSessionBindingEvent arg0) {
  239. // We are not interested in bindings
  240. }
  241. /**
  242. * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)
  243. */
  244. @Override
  245. public void valueUnbound(HttpSessionBindingEvent event) {
  246. // If we are going to be unbound from the session, the session must be
  247. // closing
  248. // Notify the service
  249. if (service == null) {
  250. getLogger().warning(
  251. "A VaadinSession instance not associated to any service is getting unbound. "
  252. + "Session destroy events will not be fired and UIs in the session will not get detached. "
  253. + "This might happen if a session is deserialized but never used before it expires.");
  254. } else if (VaadinService.getCurrentRequest() != null
  255. && getCurrent() == this) {
  256. assert hasLock();
  257. // Ignore if the session is being moved to a different backing
  258. // session or if GAEVaadinServlet is doing its normal cleanup.
  259. if (getAttribute(
  260. VaadinService.PRESERVE_UNBOUND_SESSION_ATTRIBUTE) == Boolean.TRUE) {
  261. return;
  262. }
  263. // There is still a request in progress for this session. The
  264. // session will be destroyed after the response has been written.
  265. if (getState() == State.OPEN) {
  266. close();
  267. }
  268. } else {
  269. // We are not in a request related to this session so we can destroy
  270. // it as soon as we acquire the lock.
  271. service.fireSessionDestroy(this);
  272. }
  273. session = null;
  274. }
  275. /**
  276. * Get the web browser associated with this session.
  277. *
  278. * @return the web browser object
  279. *
  280. * @deprecated As of 7.0, use {@link Page#getWebBrowser()} instead.
  281. */
  282. @Deprecated
  283. public WebBrowser getBrowser() {
  284. assert hasLock();
  285. return browser;
  286. }
  287. /**
  288. * @return The total time spent servicing requests in this session, in
  289. * milliseconds.
  290. */
  291. public long getCumulativeRequestDuration() {
  292. assert hasLock();
  293. return cumulativeRequestDuration;
  294. }
  295. /**
  296. * Sets the time spent servicing the last request in the session and updates
  297. * the total time spent servicing requests in this session.
  298. *
  299. * @param time
  300. * The time spent in the last request, in milliseconds.
  301. */
  302. public void setLastRequestDuration(long time) {
  303. assert hasLock();
  304. lastRequestDuration = time;
  305. cumulativeRequestDuration += time;
  306. }
  307. /**
  308. * @return The time spent servicing the last request in this session, in
  309. * milliseconds.
  310. */
  311. public long getLastRequestDuration() {
  312. assert hasLock();
  313. return lastRequestDuration;
  314. }
  315. /**
  316. * Sets the time when the last UIDL request was serviced in this session.
  317. *
  318. * @param timestamp
  319. * The time when the last request was handled, in milliseconds
  320. * since the epoch.
  321. *
  322. */
  323. public void setLastRequestTimestamp(long timestamp) {
  324. assert hasLock();
  325. lastRequestTimestamp = timestamp;
  326. }
  327. /**
  328. * Returns the time when the last request was serviced in this session.
  329. *
  330. * @return The time when the last request was handled, in milliseconds since
  331. * the epoch.
  332. */
  333. public long getLastRequestTimestamp() {
  334. assert hasLock();
  335. return lastRequestTimestamp;
  336. }
  337. /**
  338. * Gets the underlying session to which this service session is currently
  339. * associated.
  340. *
  341. * @return the wrapped session for this context
  342. */
  343. public WrappedSession getSession() {
  344. /*
  345. * This is used to fetch the underlying session and there is no need for
  346. * having a lock when doing this. On the contrary this is sometimes done
  347. * to be able to lock the session.
  348. */
  349. return session;
  350. }
  351. /**
  352. * @return
  353. *
  354. * @deprecated As of 7.0. Will likely change or be removed in a future
  355. * version
  356. */
  357. @Deprecated
  358. public LegacyCommunicationManager getCommunicationManager() {
  359. assert hasLock();
  360. return communicationManager;
  361. }
  362. public DragAndDropService getDragAndDropService() {
  363. if (dragAndDropService == null) {
  364. dragAndDropService = new DragAndDropService(this);
  365. }
  366. return dragAndDropService;
  367. }
  368. /**
  369. * Loads the VaadinSession for the given service and WrappedSession from the
  370. * HTTP session.
  371. *
  372. * @param service
  373. * The service the VaadinSession is associated with
  374. * @param underlyingSession
  375. * The wrapped HTTP session for the user
  376. * @return A VaadinSession instance for the service, session combination or
  377. * null if none was found.
  378. * @deprecated as of 7.6, call
  379. * {@link VaadinService#loadSession(WrappedSession)} instead
  380. */
  381. @Deprecated
  382. public static VaadinSession getForSession(VaadinService service,
  383. WrappedSession underlyingSession) {
  384. return service.loadSession(underlyingSession);
  385. }
  386. /**
  387. * Retrieves all {@link VaadinSession}s which are stored in the given HTTP
  388. * session
  389. *
  390. * @since 7.2
  391. * @param httpSession
  392. * the HTTP session
  393. * @return the found VaadinSessions
  394. */
  395. public static Collection<VaadinSession> getAllSessions(
  396. HttpSession httpSession) {
  397. Set<VaadinSession> sessions = new HashSet<>();
  398. Enumeration<String> attributeNames = httpSession.getAttributeNames();
  399. while (attributeNames.hasMoreElements()) {
  400. String attributeName = attributeNames.nextElement();
  401. if (attributeName.startsWith(VaadinSession.class.getName() + ".")) {
  402. Object value = httpSession.getAttribute(attributeName);
  403. if (value instanceof VaadinSession) {
  404. sessions.add((VaadinSession) value);
  405. }
  406. }
  407. }
  408. return sessions;
  409. }
  410. /**
  411. * Removes this VaadinSession from the HTTP session.
  412. *
  413. * @param service
  414. * The service this session is associated with
  415. * @deprecated as of 7.6, call
  416. * {@link VaadinService#removeSession(WrappedSession)} instead
  417. */
  418. @Deprecated
  419. public void removeFromSession(VaadinService service) {
  420. service.removeSession(session);
  421. }
  422. /**
  423. * Stores this VaadinSession in the HTTP session.
  424. *
  425. * @param service
  426. * The service this session is associated with
  427. * @param session
  428. * The HTTP session this VaadinSession should be stored in
  429. * @deprecated as of 7.6, call
  430. * {@link VaadinService#storeSession(VaadinSession, WrappedSession)}
  431. * instead
  432. */
  433. @Deprecated
  434. public void storeInSession(VaadinService service, WrappedSession session) {
  435. service.storeSession(this, session);
  436. }
  437. /**
  438. * Updates the transient session lock from VaadinService.
  439. */
  440. private void refreshLock() {
  441. assert lock == null || lock == service.getSessionLock(
  442. session) : "Cannot change the lock from one instance to another";
  443. assert hasLock(service, session);
  444. lock = service.getSessionLock(session);
  445. }
  446. public void setCommunicationManager(
  447. LegacyCommunicationManager communicationManager) {
  448. assert hasLock();
  449. if (communicationManager == null) {
  450. throw new IllegalArgumentException("Can not set to null");
  451. }
  452. assert this.communicationManager == null : "Communication manager can only be set once";
  453. this.communicationManager = communicationManager;
  454. }
  455. public void setConfiguration(DeploymentConfiguration configuration) {
  456. assert hasLock();
  457. if (configuration == null) {
  458. throw new IllegalArgumentException("Can not set to null");
  459. }
  460. assert this.configuration == null : "Configuration can only be set once";
  461. this.configuration = configuration;
  462. }
  463. /**
  464. * Gets the configuration for this session
  465. *
  466. * @return the deployment configuration
  467. */
  468. public DeploymentConfiguration getConfiguration() {
  469. assert hasLock();
  470. return configuration;
  471. }
  472. /**
  473. * Gets the default locale for this session.
  474. *
  475. * By default this is the preferred locale of the user using the session. In
  476. * most cases it is read from the browser defaults.
  477. *
  478. * @return the locale of this session.
  479. */
  480. public Locale getLocale() {
  481. assert hasLock();
  482. if (locale != null) {
  483. return locale;
  484. }
  485. return Locale.getDefault();
  486. }
  487. /**
  488. * Sets the default locale for this session.
  489. *
  490. * By default this is the preferred locale of the user using the
  491. * application. In most cases it is read from the browser defaults.
  492. *
  493. * @param locale
  494. * the Locale object.
  495. *
  496. */
  497. public void setLocale(Locale locale) {
  498. assert hasLock();
  499. this.locale = locale;
  500. }
  501. /**
  502. * Gets the session's error handler.
  503. *
  504. * @return the current error handler
  505. */
  506. public ErrorHandler getErrorHandler() {
  507. assert hasLock();
  508. return errorHandler;
  509. }
  510. /**
  511. * Sets the session error handler.
  512. *
  513. * @param errorHandler
  514. */
  515. public void setErrorHandler(ErrorHandler errorHandler) {
  516. assert hasLock();
  517. this.errorHandler = errorHandler;
  518. }
  519. /**
  520. * Gets the {@code ConverterFactory} used to locate a suitable
  521. * {@code Converter} for fields in the session.
  522. * <p>
  523. * Note that the this and {@link #setConverterFactory(Object))} use Object
  524. * and not {@code ConverterFactory} in Vaadin 8 to avoid a core dependency
  525. * on the compatibility packages.
  526. *
  527. * @return The converter factory used in the session
  528. */
  529. @Deprecated
  530. public Object getConverterFactory() {
  531. assert hasLock();
  532. return converterFactory;
  533. }
  534. /**
  535. * Sets the {@code ConverterFactory} used to locate a suitable
  536. * {@code Converter} for fields in the session.
  537. * <p>
  538. * The {@code ConverterFactory} is used to find a suitable converter when
  539. * binding data to a UI component and the data type does not match the UI
  540. * component type, e.g. binding a Double to a TextField (which is based on a
  541. * String).
  542. * <p>
  543. * Note that the this and {@code #getConverterFactory()} use Object and not
  544. * {@code ConverterFactory} in Vaadin 8 to avoid a core dependency on the
  545. * compatibility packages.
  546. * <p>
  547. * The converter factory must never be set to null.
  548. *
  549. * @param converterFactory
  550. * The converter factory used in the session
  551. */
  552. @Deprecated
  553. public void setConverterFactory(Object converterFactory) {
  554. assert hasLock();
  555. this.converterFactory = converterFactory;
  556. }
  557. /**
  558. * Adds a request handler to this session. Request handlers can be added to
  559. * provide responses to requests that are not handled by the default
  560. * functionality of the framework.
  561. * <p>
  562. * Handlers are called in reverse order of addition, so the most recently
  563. * added handler will be called first.
  564. * </p>
  565. *
  566. * @param handler
  567. * the request handler to add
  568. *
  569. * @see #removeRequestHandler(RequestHandler)
  570. *
  571. * @since 7.0
  572. */
  573. public void addRequestHandler(RequestHandler handler) {
  574. assert hasLock();
  575. requestHandlers.addFirst(handler);
  576. }
  577. /**
  578. * Removes a request handler from the session.
  579. *
  580. * @param handler
  581. * the request handler to remove
  582. *
  583. * @since 7.0
  584. */
  585. public void removeRequestHandler(RequestHandler handler) {
  586. assert hasLock();
  587. requestHandlers.remove(handler);
  588. }
  589. /**
  590. * Gets the request handlers that are registered to the session. The
  591. * iteration order of the returned collection is the same as the order in
  592. * which the request handlers will be invoked when a request is handled.
  593. *
  594. * @return a collection of request handlers, with the iteration order
  595. * according to the order they would be invoked
  596. *
  597. * @see #addRequestHandler(RequestHandler)
  598. * @see #removeRequestHandler(RequestHandler)
  599. *
  600. * @since 7.0
  601. */
  602. public Collection<RequestHandler> getRequestHandlers() {
  603. assert hasLock();
  604. return Collections.unmodifiableCollection(requestHandlers);
  605. }
  606. /**
  607. * Gets the currently used session. The current session is automatically
  608. * defined when processing requests related to the session (see
  609. * {@link ThreadLocal}) and in {@link VaadinSession#access(Command)} and
  610. * {@link UI#access(Command)}. In other cases, (e.g. from background
  611. * threads, the current session is not automatically defined.
  612. * <p>
  613. * The session is stored using a weak reference to avoid leaking memory in
  614. * case it is not explicitly cleared.
  615. *
  616. * @return the current session instance if available, otherwise
  617. * <code>null</code>
  618. *
  619. * @see #setCurrent(VaadinSession)
  620. *
  621. * @since 7.0
  622. */
  623. public static VaadinSession getCurrent() {
  624. return CurrentInstance.get(VaadinSession.class);
  625. }
  626. /**
  627. * Sets the thread local for the current session. This method is used by the
  628. * framework to set the current session whenever a new request is processed
  629. * and it is cleared when the request has been processed.
  630. * <p>
  631. * The application developer can also use this method to define the current
  632. * session outside the normal request handling and treads started from
  633. * request handling threads, e.g. when initiating custom background threads.
  634. * <p>
  635. * The session is stored using a weak reference to avoid leaking memory in
  636. * case it is not explicitly cleared.
  637. *
  638. * @param session
  639. * the session to set as current
  640. *
  641. * @see #getCurrent()
  642. * @see ThreadLocal
  643. *
  644. * @since 7.0
  645. */
  646. public static void setCurrent(VaadinSession session) {
  647. CurrentInstance.set(VaadinSession.class, session);
  648. }
  649. /**
  650. * Gets all the UIs of this session. This includes UIs that have been
  651. * requested but not yet initialized. UIs that receive no heartbeat requests
  652. * from the client are eventually removed from the session.
  653. *
  654. * @return a collection of UIs belonging to this application
  655. *
  656. * @since 7.0
  657. */
  658. public Collection<UI> getUIs() {
  659. assert hasLock();
  660. return Collections.unmodifiableCollection(uIs.values());
  661. }
  662. private int connectorIdSequence = 0;
  663. /*
  664. * Despite section 6 of RFC 4122, this particular use of UUID *is* adequate
  665. * for security capabilities. Type 4 UUIDs contain 122 bits of random data,
  666. * and UUID.randomUUID() is defined to use a cryptographically secure random
  667. * generator.
  668. */
  669. private final String csrfToken = UUID.randomUUID().toString();
  670. /**
  671. * Generate an id for the given Connector. Connectors must not call this
  672. * method more than once, the first time they need an id.
  673. *
  674. * @param connector
  675. * A connector that has not yet been assigned an id.
  676. * @return A new id for the connector
  677. *
  678. * @deprecated As of 7.0. Will likely change or be removed in a future
  679. * version
  680. */
  681. @Deprecated
  682. public String createConnectorId(ClientConnector connector) {
  683. assert hasLock();
  684. return String.valueOf(connectorIdSequence++);
  685. }
  686. /**
  687. * Returns a UI with the given id.
  688. * <p>
  689. * This is meant for framework internal use.
  690. * </p>
  691. *
  692. * @param uiId
  693. * The UI id
  694. * @return The UI with the given id or null if not found
  695. */
  696. public UI getUIById(int uiId) {
  697. assert hasLock();
  698. return uIs.get(uiId);
  699. }
  700. /**
  701. * Checks if the current thread has exclusive access to this VaadinSession
  702. *
  703. * @return true if the thread has exclusive access, false otherwise
  704. * @since 7.1
  705. */
  706. public boolean hasLock() {
  707. ReentrantLock l = ((ReentrantLock) getLockInstance());
  708. return l.isHeldByCurrentThread();
  709. }
  710. /**
  711. * Checks if the current thread has exclusive access to the given
  712. * WrappedSession.
  713. *
  714. * @return true if this thread has exclusive access, false otherwise
  715. * @since 7.6
  716. */
  717. protected static boolean hasLock(VaadinService service,
  718. WrappedSession session) {
  719. ReentrantLock l = (ReentrantLock) service.getSessionLock(session);
  720. return l.isHeldByCurrentThread();
  721. }
  722. /**
  723. * Adds a listener that will be invoked when the bootstrap HTML is about to
  724. * be generated. This can be used to modify the contents of the HTML that
  725. * loads the Vaadin application in the browser and the HTTP headers that are
  726. * included in the response serving the HTML.
  727. *
  728. * @see BootstrapListener#modifyBootstrapFragment(BootstrapFragmentResponse)
  729. * @see BootstrapListener#modifyBootstrapPage(BootstrapPageResponse)
  730. *
  731. * @param listener
  732. * the bootstrap listener to add
  733. * @return a registration object for removing the listener
  734. */
  735. public Registration addBootstrapListener(BootstrapListener listener) {
  736. assert hasLock();
  737. eventRouter.addListener(BootstrapFragmentResponse.class, listener,
  738. BOOTSTRAP_FRAGMENT_METHOD);
  739. eventRouter.addListener(BootstrapPageResponse.class, listener,
  740. BOOTSTRAP_PAGE_METHOD);
  741. return () -> {
  742. eventRouter.removeListener(BootstrapFragmentResponse.class,
  743. listener, BOOTSTRAP_FRAGMENT_METHOD);
  744. eventRouter.removeListener(BootstrapPageResponse.class, listener,
  745. BOOTSTRAP_PAGE_METHOD);
  746. };
  747. }
  748. /**
  749. * Remove a bootstrap listener that was previously added.
  750. *
  751. * @see #addBootstrapListener(BootstrapListener)
  752. *
  753. * @param listener
  754. * the bootstrap listener to remove
  755. * @deprecated Use a {@link Registration} object returned by
  756. * {@link #addBootstrapListener(BootstrapListener)} to remove a
  757. * listener
  758. */
  759. @Deprecated
  760. public void removeBootstrapListener(BootstrapListener listener) {
  761. assert hasLock();
  762. eventRouter.removeListener(BootstrapFragmentResponse.class, listener,
  763. BOOTSTRAP_FRAGMENT_METHOD);
  764. eventRouter.removeListener(BootstrapPageResponse.class, listener,
  765. BOOTSTRAP_PAGE_METHOD);
  766. }
  767. /**
  768. * Fires a bootstrap event to all registered listeners. There are currently
  769. * two supported events, both inheriting from {@link BootstrapResponse}:
  770. * {@link BootstrapFragmentResponse} and {@link BootstrapPageResponse}.
  771. *
  772. * @param response
  773. * the bootstrap response event for which listeners should be
  774. * fired
  775. *
  776. * @deprecated As of 7.0. Will likely change or be removed in a future
  777. * version
  778. */
  779. @Deprecated
  780. public void modifyBootstrapResponse(BootstrapResponse response) {
  781. assert hasLock();
  782. eventRouter.fireEvent(response);
  783. }
  784. /**
  785. * Called by the framework to remove an UI instance from the session because
  786. * it has been closed.
  787. *
  788. * @param ui
  789. * the UI to remove
  790. */
  791. public void removeUI(UI ui) {
  792. assert hasLock();
  793. assert UI.getCurrent() == ui;
  794. Integer id = Integer.valueOf(ui.getUIId());
  795. ui.setSession(null);
  796. uIs.remove(id);
  797. String embedId = ui.getEmbedId();
  798. if (embedId != null && id.equals(embedIdMap.get(embedId))) {
  799. embedIdMap.remove(embedId);
  800. }
  801. }
  802. /**
  803. * Gets this session's global resource handler that takes care of serving
  804. * connector resources that are not served by any single connector because
  805. * e.g. because they are served with strong caching or because of legacy
  806. * reasons.
  807. *
  808. * @param createOnDemand
  809. * <code>true</code> if a resource handler should be initialized
  810. * if there is no handler associated with this application.
  811. * </code>false</code> if </code>null</code> should be returned
  812. * if there is no registered handler.
  813. * @return this session's global resource handler, or <code>null</code> if
  814. * there is no handler and the createOnDemand parameter is
  815. * <code>false</code>.
  816. *
  817. * @since 7.0.0
  818. */
  819. public GlobalResourceHandler getGlobalResourceHandler(
  820. boolean createOnDemand) {
  821. assert hasLock();
  822. if (globalResourceHandler == null && createOnDemand) {
  823. globalResourceHandler = new GlobalResourceHandler();
  824. addRequestHandler(globalResourceHandler);
  825. }
  826. return globalResourceHandler;
  827. }
  828. /**
  829. * Gets the {@link Lock} instance that is used for protecting the data of
  830. * this session from concurrent access.
  831. * <p>
  832. * The <code>Lock</code> can be used to gain more control than what is
  833. * available only using {@link #lock()} and {@link #unlock()}. The returned
  834. * instance is not guaranteed to support any other features of the
  835. * <code>Lock</code> interface than {@link Lock#lock()} and
  836. * {@link Lock#unlock()}.
  837. *
  838. * @return the <code>Lock</code> that is used for synchronization, never
  839. * <code>null</code>
  840. *
  841. * @see #lock()
  842. * @see Lock
  843. */
  844. public Lock getLockInstance() {
  845. return lock;
  846. }
  847. /**
  848. * Locks this session to protect its data from concurrent access. Accessing
  849. * the UI state from outside the normal request handling should always lock
  850. * the session and unlock it when done. The preferred way to ensure locking
  851. * is done correctly is to wrap your code using {@link UI#access(Runnable)}
  852. * (or {@link VaadinSession#access(Runnable)} if you are only touching the
  853. * session and not any UI), e.g.:
  854. *
  855. * <pre>
  856. * myUI.access(new Runnable() {
  857. * &#064;Override
  858. * public void run() {
  859. * // Here it is safe to update the UI.
  860. * // UI.getCurrent can also be used
  861. * myUI.getContent().setCaption(&quot;Changed safely&quot;);
  862. * }
  863. * });
  864. * </pre>
  865. *
  866. * If you for whatever reason want to do locking manually, you should do it
  867. * like:
  868. *
  869. * <pre>
  870. * session.lock();
  871. * try {
  872. * doSomething();
  873. * } finally {
  874. * session.unlock();
  875. * }
  876. * </pre>
  877. *
  878. * This method will block until the lock can be retrieved.
  879. * <p>
  880. * {@link #getLockInstance()} can be used if more control over the locking
  881. * is required.
  882. *
  883. * @see #unlock()
  884. * @see #getLockInstance()
  885. * @see #hasLock()
  886. */
  887. public void lock() {
  888. getLockInstance().lock();
  889. }
  890. /**
  891. * Unlocks this session. This method should always be used in a finally
  892. * block after {@link #lock()} to ensure that the lock is always released.
  893. * <p>
  894. * For UIs in this session that have its push mode set to
  895. * {@link PushMode#AUTOMATIC automatic}, pending changes will be pushed to
  896. * their respective clients.
  897. *
  898. * @see #lock()
  899. * @see UI#push()
  900. */
  901. public void unlock() {
  902. assert hasLock();
  903. boolean ultimateRelease = false;
  904. try {
  905. /*
  906. * Run pending tasks and push if the reentrant lock will actually be
  907. * released by this unlock() invocation.
  908. */
  909. if (((ReentrantLock) getLockInstance()).getHoldCount() == 1) {
  910. ultimateRelease = true;
  911. getService().runPendingAccessTasks(this);
  912. for (UI ui : getUIs()) {
  913. if (ui.getPushConfiguration()
  914. .getPushMode() == PushMode.AUTOMATIC) {
  915. Map<Class<?>, CurrentInstance> oldCurrent = CurrentInstance
  916. .setCurrent(ui);
  917. try {
  918. ui.push();
  919. } finally {
  920. CurrentInstance.restoreInstances(oldCurrent);
  921. }
  922. }
  923. }
  924. }
  925. } finally {
  926. getLockInstance().unlock();
  927. }
  928. /*
  929. * If the session is locked when a new access task is added, it is
  930. * assumed that the queue will be purged when the lock is released. This
  931. * might however not happen if a task is enqueued between the moment
  932. * when unlock() purges the queue and the moment when the lock is
  933. * actually released. This means that the queue should be purged again
  934. * if it is not empty after unlocking.
  935. */
  936. if (ultimateRelease && !getPendingAccessQueue().isEmpty()) {
  937. getService().ensureAccessQueuePurged(this);
  938. }
  939. }
  940. /**
  941. * Stores a value in this service session. This can be used to associate
  942. * data with the current user so that it can be retrieved at a later point
  943. * from some other part of the application. Setting the value to
  944. * <code>null</code> clears the stored value.
  945. *
  946. * @see #getAttribute(String)
  947. *
  948. * @param name
  949. * the name to associate the value with, can not be
  950. * <code>null</code>
  951. * @param value
  952. * the value to associate with the name, or <code>null</code> to
  953. * remove a previous association.
  954. */
  955. public void setAttribute(String name, Object value) {
  956. assert hasLock();
  957. if (name == null) {
  958. throw new IllegalArgumentException("name can not be null");
  959. }
  960. if (value != null) {
  961. attributes.put(name, value);
  962. } else {
  963. attributes.remove(name);
  964. }
  965. }
  966. /**
  967. * Stores a value in this service session. This can be used to associate
  968. * data with the current user so that it can be retrieved at a later point
  969. * from some other part of the application. Setting the value to
  970. * <code>null</code> clears the stored value.
  971. * <p>
  972. * The fully qualified name of the type is used as the name when storing the
  973. * value. The outcome of calling this method is thus the same as if
  974. * calling<br />
  975. * <br />
  976. * <code>setAttribute(type.getName(), value);</code>
  977. *
  978. * @see #getAttribute(Class)
  979. * @see #setAttribute(String, Object)
  980. *
  981. * @param type
  982. * the type that the stored value represents, can not be null
  983. * @param value
  984. * the value to associate with the type, or <code>null</code> to
  985. * remove a previous association.
  986. */
  987. public <T> void setAttribute(Class<T> type, T value) {
  988. assert hasLock();
  989. if (type == null) {
  990. throw new IllegalArgumentException("type can not be null");
  991. }
  992. if (value != null && !type.isInstance(value)) {
  993. throw new IllegalArgumentException("value of type " + type.getName()
  994. + " expected but got " + value.getClass().getName());
  995. }
  996. setAttribute(type.getName(), value);
  997. }
  998. /**
  999. * Gets a stored attribute value. If a value has been stored for the
  1000. * session, that value is returned. If no value is stored for the name,
  1001. * <code>null</code> is returned.
  1002. *
  1003. * @see #setAttribute(String, Object)
  1004. *
  1005. * @param name
  1006. * the name of the value to get, can not be <code>null</code>.
  1007. * @return the value, or <code>null</code> if no value has been stored or if
  1008. * it has been set to null.
  1009. */
  1010. public Object getAttribute(String name) {
  1011. assert hasLock();
  1012. if (name == null) {
  1013. throw new IllegalArgumentException("name can not be null");
  1014. }
  1015. return attributes.get(name);
  1016. }
  1017. /**
  1018. * Gets a stored attribute value. If a value has been stored for the
  1019. * session, that value is returned. If no value is stored for the name,
  1020. * <code>null</code> is returned.
  1021. * <p>
  1022. * The fully qualified name of the type is used as the name when getting the
  1023. * value. The outcome of calling this method is thus the same as if
  1024. * calling<br />
  1025. * <br />
  1026. * <code>getAttribute(type.getName());</code>
  1027. *
  1028. * @see #setAttribute(Class, Object)
  1029. * @see #getAttribute(String)
  1030. *
  1031. * @param type
  1032. * the type of the value to get, can not be <code>null</code>.
  1033. * @return the value, or <code>null</code> if no value has been stored or if
  1034. * it has been set to null.
  1035. */
  1036. public <T> T getAttribute(Class<T> type) {
  1037. assert hasLock();
  1038. if (type == null) {
  1039. throw new IllegalArgumentException("type can not be null");
  1040. }
  1041. Object value = getAttribute(type.getName());
  1042. if (value == null) {
  1043. return null;
  1044. } else {
  1045. return type.cast(value);
  1046. }
  1047. }
  1048. /**
  1049. * Creates a new unique id for a UI.
  1050. *
  1051. * @return a unique UI id
  1052. */
  1053. public int getNextUIid() {
  1054. assert hasLock();
  1055. return nextUIId++;
  1056. }
  1057. /**
  1058. * Adds an initialized UI to this session.
  1059. *
  1060. * @param ui
  1061. * the initialized UI to add.
  1062. */
  1063. public void addUI(UI ui) {
  1064. assert hasLock();
  1065. if (ui.getUIId() == -1) {
  1066. throw new IllegalArgumentException(
  1067. "Can not add an UI that has not been initialized.");
  1068. }
  1069. if (ui.getSession() != this) {
  1070. throw new IllegalArgumentException(
  1071. "The UI belongs to a different session");
  1072. }
  1073. Integer uiId = Integer.valueOf(ui.getUIId());
  1074. uIs.put(uiId, ui);
  1075. String embedId = ui.getEmbedId();
  1076. if (embedId != null) {
  1077. Integer previousUiId = embedIdMap.put(embedId, uiId);
  1078. if (previousUiId != null) {
  1079. UI previousUi = uIs.get(previousUiId);
  1080. assert previousUi != null && embedId.equals(previousUi
  1081. .getEmbedId()) : "UI id map and embed id map not in sync";
  1082. // Will fire cleanup events at the end of the request handling.
  1083. previousUi.close();
  1084. }
  1085. }
  1086. }
  1087. /**
  1088. * Adds a UI provider to this session.
  1089. *
  1090. * @param uiProvider
  1091. * the UI provider that should be added
  1092. */
  1093. public void addUIProvider(UIProvider uiProvider) {
  1094. assert hasLock();
  1095. uiProviders.addFirst(uiProvider);
  1096. }
  1097. /**
  1098. * Removes a UI provider association from this session.
  1099. *
  1100. * @param uiProvider
  1101. * the UI provider that should be removed
  1102. */
  1103. public void removeUIProvider(UIProvider uiProvider) {
  1104. assert hasLock();
  1105. uiProviders.remove(uiProvider);
  1106. }
  1107. /**
  1108. * Gets the UI providers configured for this session.
  1109. *
  1110. * @return an unmodifiable list of UI providers
  1111. */
  1112. public List<UIProvider> getUIProviders() {
  1113. assert hasLock();
  1114. return Collections.unmodifiableList(uiProviders);
  1115. }
  1116. public VaadinService getService() {
  1117. return service;
  1118. }
  1119. /**
  1120. * Sets this session to be closed and all UI state to be discarded at the
  1121. * end of the current request, or at the end of the next request if there is
  1122. * no ongoing one.
  1123. * <p>
  1124. * After the session has been discarded, any UIs that have been left open
  1125. * will give a Session Expired error and a new session will be created for
  1126. * serving new UIs.
  1127. * <p>
  1128. * To avoid causing out of sync errors, you should typically redirect to
  1129. * some other page using {@link Page#setLocation(String)} to make the
  1130. * browser unload the invalidated UI.
  1131. *
  1132. * @see SystemMessages#getSessionExpiredCaption()
  1133. *
  1134. */
  1135. public void close() {
  1136. assert hasLock();
  1137. state = State.CLOSING;
  1138. }
  1139. /**
  1140. * Returns whether this session is marked to be closed. Note that this
  1141. * method also returns true if the session is actually already closed.
  1142. *
  1143. * @see #close()
  1144. *
  1145. * @deprecated As of 7.2, use
  1146. * <code>{@link #getState() getState() != State.OPEN}</code>
  1147. * instead.
  1148. *
  1149. * @return true if this session is marked to be closed, false otherwise
  1150. */
  1151. @Deprecated
  1152. public boolean isClosing() {
  1153. assert hasLock();
  1154. return state == State.CLOSING || state == State.CLOSED;
  1155. }
  1156. /**
  1157. * Returns the lifecycle state of this session.
  1158. *
  1159. * @since 7.2
  1160. * @return the current state
  1161. */
  1162. public State getState() {
  1163. assert hasLock();
  1164. return state;
  1165. }
  1166. /**
  1167. * Sets the lifecycle state of this session. The allowed transitions are
  1168. * OPEN to CLOSING and CLOSING to CLOSED.
  1169. *
  1170. * @since 7.2
  1171. * @param state
  1172. * the new state
  1173. */
  1174. protected void setState(State state) {
  1175. assert hasLock();
  1176. assert this.state.isValidChange(state) : "Invalid session state change "
  1177. + this.state + "->" + state;
  1178. this.state = state;
  1179. }
  1180. private static final Logger getLogger() {
  1181. return Logger.getLogger(VaadinSession.class.getName());
  1182. }
  1183. /**
  1184. * Locks this session and runs the provided Runnable right away.
  1185. * <p>
  1186. * It is generally recommended to use {@link #access(Runnable)} instead of
  1187. * this method for accessing a session from a different thread as
  1188. * {@link #access(Runnable)} can be used while holding the lock of another
  1189. * session. To avoid causing deadlocks, this methods throws an exception if
  1190. * it is detected than another session is also locked by the current thread.
  1191. * </p>
  1192. * <p>
  1193. * This method behaves differently than {@link #access(Runnable)} in some
  1194. * situations:
  1195. * <ul>
  1196. * <li>If the current thread is currently holding the lock of this session,
  1197. * {@link #accessSynchronously(Runnable)} runs the task right away whereas
  1198. * {@link #access(Runnable)} defers the task to a later point in time.</li>
  1199. * <li>If some other thread is currently holding the lock for this session,
  1200. * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock
  1201. * to be available whereas {@link #access(Runnable)} defers the task to a
  1202. * later point in time.</li>
  1203. * </ul>
  1204. * </p>
  1205. *
  1206. * @param runnable
  1207. * the runnable which accesses the session
  1208. *
  1209. * @throws IllegalStateException
  1210. * if the current thread holds the lock for another session
  1211. *
  1212. * @since 7.1
  1213. *
  1214. * @see #lock()
  1215. * @see #getCurrent()
  1216. * @see #access(Runnable)
  1217. * @see UI#accessSynchronously(Runnable)
  1218. */
  1219. public void accessSynchronously(Runnable runnable) {
  1220. VaadinService.verifyNoOtherSessionLocked(this);
  1221. Map<Class<?>, CurrentInstance> old = null;
  1222. lock();
  1223. try {
  1224. old = CurrentInstance.setCurrent(this);
  1225. runnable.run();
  1226. } finally {
  1227. unlock();
  1228. if (old != null) {
  1229. CurrentInstance.restoreInstances(old);
  1230. }
  1231. }
  1232. }
  1233. /**
  1234. * Provides exclusive access to this session from outside a request handling
  1235. * thread.
  1236. * <p>
  1237. * The given runnable is executed while holding the session lock to ensure
  1238. * exclusive access to this session. If this session is not locked, the lock
  1239. * will be acquired and the runnable is run right away. If this session is
  1240. * currently locked, the runnable will be run before that lock is released.
  1241. * </p>
  1242. * <p>
  1243. * RPC handlers for components inside this session do not need to use this
  1244. * method as the session is automatically locked by the framework during RPC
  1245. * handling.
  1246. * </p>
  1247. * <p>
  1248. * Please note that the runnable might be invoked on a different thread or
  1249. * later on the current thread, which means that custom thread locals might
  1250. * not have the expected values when the command is executed.
  1251. * {@link VaadinSession#getCurrent()} and {@link VaadinService#getCurrent()}
  1252. * are set according to this session before executing the command. Other
  1253. * standard CurrentInstance values such as
  1254. * {@link VaadinService#getCurrentRequest()} and
  1255. * {@link VaadinService#getCurrentResponse()} will not be defined.
  1256. * </p>
  1257. * <p>
  1258. * The returned future can be used to check for task completion and to
  1259. * cancel the task. To help avoiding deadlocks, {@link Future#get()} throws
  1260. * an exception if it is detected that the current thread holds the lock for
  1261. * some other session.
  1262. * </p>
  1263. *
  1264. * @see #lock()
  1265. * @see #getCurrent()
  1266. * @see #accessSynchronously(Runnable)
  1267. * @see UI#access(Runnable)
  1268. *
  1269. * @since 7.1
  1270. *
  1271. * @param runnable
  1272. * the runnable which accesses the session
  1273. * @return a future that can be used to check for task completion and to
  1274. * cancel the task
  1275. */
  1276. public Future<Void> access(Runnable runnable) {
  1277. return getService().accessSession(this, runnable);
  1278. }
  1279. /**
  1280. * Gets the queue of tasks submitted using {@link #access(Runnable)}. It is
  1281. * safe to call this method and access the returned queue without holding
  1282. * the {@link #lock() session lock}.
  1283. *
  1284. * @since 7.1
  1285. *
  1286. * @return the queue of pending access tasks
  1287. */
  1288. public Queue<FutureAccess> getPendingAccessQueue() {
  1289. return pendingAccessQueue;
  1290. }
  1291. /**
  1292. * Gets the CSRF token (aka double submit cookie) that is used to protect
  1293. * against Cross Site Request Forgery attacks.
  1294. *
  1295. * @since 7.1
  1296. * @return the csrf token string
  1297. */
  1298. public String getCsrfToken() {
  1299. assert hasLock();
  1300. return csrfToken;
  1301. }
  1302. /**
  1303. * Override default deserialization logic to account for transient
  1304. * {@link #pendingAccessQueue}.
  1305. */
  1306. private void readObject(ObjectInputStream stream)
  1307. throws IOException, ClassNotFoundException {
  1308. Map<Class<?>, CurrentInstance> old = CurrentInstance.setCurrent(this);
  1309. try {
  1310. stream.defaultReadObject();
  1311. pendingAccessQueue = new ConcurrentLinkedQueue<>();
  1312. } finally {
  1313. CurrentInstance.restoreInstances(old);
  1314. }
  1315. }
  1316. /**
  1317. * Override default serialization logic to avoid
  1318. * ConcurrentModificationException if the contents are modified while
  1319. * serialization is reading them.
  1320. */
  1321. private void writeObject(ObjectOutputStream out) throws IOException {
  1322. Lock lock = this.lock;
  1323. if (lock != null) {
  1324. lock.lock();
  1325. }
  1326. try {
  1327. out.defaultWriteObject();
  1328. } finally {
  1329. if (lock != null) {
  1330. lock.unlock();
  1331. }
  1332. }
  1333. }
  1334. /**
  1335. * Finds the UI with the corresponding embed id.
  1336. *
  1337. * @since 7.2
  1338. * @param embedId
  1339. * the embed id
  1340. * @return the UI with the corresponding embed id, or <code>null</code> if
  1341. * no UI is found
  1342. *
  1343. * @see UI#getEmbedId()
  1344. */
  1345. public UI getUIByEmbedId(String embedId) {
  1346. Integer uiId = embedIdMap.get(embedId);
  1347. if (uiId == null) {
  1348. return null;
  1349. } else {
  1350. return getUIById(uiId.intValue());
  1351. }
  1352. }
  1353. /**
  1354. * Refreshes the transient fields of the session to ensure they are up to
  1355. * date.
  1356. * <p>
  1357. * Called internally by the framework.
  1358. *
  1359. * @since 7.6
  1360. * @param wrappedSession
  1361. * the session this VaadinSession is stored in
  1362. * @param vaadinService
  1363. * the service associated with this VaadinSession
  1364. */
  1365. public void refreshTransients(WrappedSession wrappedSession,
  1366. VaadinService vaadinService) {
  1367. session = wrappedSession;
  1368. service = vaadinService;
  1369. refreshLock();
  1370. }
  1371. }