As a part of library implementing websocket Guice scopes I need to maintain an object related to each HttpSession
called sessionContextAttributes
. Currently sessionContextAttributes
is stored as an attribute of a session, which means the access and initialization needs to be synchronized:
ConcurrentMap<Key<?>, Object> getHttpSessionContextAttributes() {
HttpSession session = getHttpSession();
try {
synchronized (session) {
@SuppressWarnings("unchecked")
var sessionContextAttributes = (ConcurrentMap<Key<?>, Object>)
session.getAttribute(SESSION_CONTEXT_ATTRIBUTE_NAME);
if (sessionContextAttributes == null) {
sessionContextAttributes = new ConcurrentHashMap<>();
session.setAttribute(SESSION_CONTEXT_ATTRIBUTE_NAME, sessionContextAttributes);
}
return sessionContextAttributes;
}
} catch (NullPointerException e) { /* ... */ }
}
static final String SESSION_CONTEXT_ATTRIBUTE_NAME =
ContainerCallContext.class.getPackageName() + ".contextAttributes";
Now I'm considering to maintain a static ConcurrentMap
from HttpSession
to sessionContextAttributes
like this:
static final ConcurrentMap<HttpSession, ConcurrentMap<Key<?>, Object>> sessionCtxs =
new ConcurrentHashMap<>();
ConcurrentMap<Key<?>, Object> getHttpSessionContextAttributes() {
try {
return sessionCtxs.computeIfAbsent(
getHttpSession(), (ignored) -> new ConcurrentHashMap<>());
} catch (NullPointerException e) { /* ... */ }
}
This simplifies getHttpSessionContextAttributes()
method and is probably slightly faster, BUT introduces static data AND requires manual removal to prevent leaking of sessionContextAttributes
:
static class SessionContextJanitor implements HttpSessionListener {
@Override
public void sessionDestroyed(HttpSessionEvent event) {
sessionCtxs.remove(event.getSession()); // this avoids resource leaks
}
}
I cannot confidently tell which approach is better: both have pros&cons. Hence I'm posting it here for review: maybe someone knows some reasons that make 1 of these approaches significantly better than the other.