Fix AbstractStompSessionManager race condition

https://build.spring.io/browse/INT-MJATS41-1150

When we add `addHandler()` to the `CompositeStompSessionHandler`,
there is no guarantee that we will have `session` atomically during
this method invocation or after it relying on the later call to the
`this.delegates`.
In other words the session may be populated in between and, therefore,
our `delegate` loses `afterConnected()` event.
We need to synchronize on the barrier and block the concurrent
`afterConnected()` or wait for it.
This way we atomically ensure that our `delegate` is added to the
existing `session` or will be performed afterwards in the `afterConnected()`

**Cherry-pick to 4.3.x**
This commit is contained in:
Artem Bilan
2017-10-23 13:45:05 -04:00
parent d7d56a0444
commit df109410c3

View File

@@ -370,10 +370,12 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
} }
void addHandler(StompSessionHandler delegate) { void addHandler(StompSessionHandler delegate) {
if (this.session != null) { synchronized (this.delegates) {
delegate.afterConnected(this.session, getConnectHeaders()); if (this.session != null) {
delegate.afterConnected(this.session, getConnectHeaders());
}
this.delegates.add(delegate);
} }
this.delegates.add(delegate);
} }
void removeHandler(StompSessionHandler delegate) { void removeHandler(StompSessionHandler delegate) {
@@ -382,8 +384,8 @@ public abstract class AbstractStompSessionManager implements StompSessionManager
@Override @Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) { public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
this.session = session;
synchronized (this.delegates) { synchronized (this.delegates) {
this.session = session;
for (StompSessionHandler delegate : this.delegates) { for (StompSessionHandler delegate : this.delegates) {
delegate.afterConnected(session, connectedHeaders); delegate.afterConnected(session, connectedHeaders);
} }