Change-Id: Ic8571b0d078c3ff64e8b9914e55c51766ae49024tags/7.1.0
@@ -1540,6 +1540,25 @@ public abstract class VaadinService implements Serializable { | |||
return false; | |||
} | |||
/** | |||
* Checks that another {@link VaadinSession} instance is not locked. This is | |||
* internally used by {@link VaadinSession#access(Runnable)} and | |||
* {@link UI#access(Runnable)} to help avoid causing deadlocks. | |||
* | |||
* @since 7.1 | |||
* @param session | |||
* the session that is being locked | |||
* @throws IllegalStateException | |||
* if the current thread holds the lock for another session | |||
*/ | |||
public static void verifyNoOtherSessionLocked(VaadinSession session) { | |||
VaadinSession otherSession = VaadinSession.getCurrent(); | |||
if (otherSession != null && otherSession != session) { | |||
throw new IllegalStateException( | |||
"Can't access session while another session is locked by the same thread. This restriction is intended to help avoid deadlocks."); | |||
} | |||
} | |||
/** | |||
* Verifies that the given CSRF token (aka double submit cookie) is valid | |||
* for the given session. This is used to protect against Cross Site Request |
@@ -1075,15 +1075,27 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { | |||
* as the session is automatically locked by the framework during request | |||
* handling. | |||
* </p> | |||
* <p> | |||
* Note that calling this method while another session is locked by the | |||
* current thread will cause an exception. This is to prevent deadlock | |||
* situations when two threads have locked one session each and are both | |||
* waiting for the lock for the other session. | |||
* </p> | |||
* | |||
* @param runnable | |||
* the runnable which accesses the session | |||
* | |||
* @throws IllegalStateException | |||
* if the current thread holds the lock for another session | |||
* | |||
* | |||
* @see #lock() | |||
* @see #getCurrent() | |||
* @see UI#access(Runnable) | |||
*/ | |||
public void access(Runnable runnable) { | |||
VaadinService.verifyNoOtherSessionLocked(this); | |||
Map<Class<?>, CurrentInstance> old = null; | |||
lock(); | |||
try { |
@@ -1103,12 +1103,20 @@ public abstract class UI extends AbstractSingleComponentContainer implements | |||
* RPC handlers for components inside this UI do not need this method as the | |||
* session is automatically locked by the framework during request handling. | |||
* </p> | |||
* <p> | |||
* Note that calling this method while another session is locked by the | |||
* current thread will cause an exception. This is to prevent deadlock | |||
* situations when two threads have locked one session each and are both | |||
* waiting for the lock for the other session. | |||
* </p> | |||
* | |||
* @param runnable | |||
* the runnable which accesses the UI | |||
* @throws UIDetachedException | |||
* if the UI is not attached to a session (and locking can | |||
* therefore not be done) | |||
* @throws IllegalStateException | |||
* if the current thread holds the lock for another session | |||
* | |||
* @see #getCurrent() | |||
* @see VaadinSession#access(Runnable) | |||
@@ -1123,6 +1131,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements | |||
throw new UIDetachedException(); | |||
} | |||
VaadinService.verifyNoOtherSessionLocked(session); | |||
session.lock(); | |||
try { | |||
if (getSession() == null) { |