I want to turn off serialization in my Wicket app and store all page/session information in RAM. My application has a very small number of users (generally 1); I do not need
I want to improve Jesse's answer. Below is a thread-safe implementation of IPageStore with internal "Least Recently Inserted" cache (keeps at most 5 recently accessed stateful pages per session):
public class CustomPageStore implements IPageStore {
private static final Logger logger = LoggerFactory.getLogger(CustomPageStore.class);
private static final int MEDIAN_OF_NUMBER_OF_SESSIONS = 6000;
private ConcurrentMap> cache = new ConcurrentHashMap<>(MEDIAN_OF_NUMBER_OF_SESSIONS);
@Override
public void destroy() {
cache.clear();
}
@Override
public IManageablePage getPage(final String sessionId, int pageId) {
final Map sessionCache = getSessionCache(sessionId);
final RequestCycle requestCycle = RequestCycle.get();
if (sessionCache == null) {
logger.warn("Missing cache. SessionId: {}, pageId: {}, URL: {}", sessionId, pageId, requestCycle == null ? StringUtils.EMPTY : requestCycle.getRequest().getUrl());
return null;
}
final IManageablePage page;
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionCache) {
page = sessionCache.get(pageId);
}
if (page == null && logger.isDebugEnabled()) {
logger.debug("Missed page. SessionId: {}, pageId: {}, URL: {}", sessionId, pageId, requestCycle == null ? StringUtils.EMPTY : requestCycle.getRequest().getUrl());
}
return page;
}
@Override
public void removePage(final String sessionId, int pageId) {
final Map sessionCache = getSessionCache(sessionId);
if (sessionCache != null) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionCache) {
sessionCache.remove(pageId);
}
}
}
@Override
public void storePage(final String sessionId, IManageablePage page) {
final LinkedHashMap sessionCache = getOrCreateSessionCache(sessionId);
final int pageId = page.getPageId();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (sessionCache) {
if (sessionCache.containsKey(pageId)) {
// do this to change insertion order and update least inserted entry
sessionCache.remove(pageId);
sessionCache.put(pageId, page);
} else {
sessionCache.put(pageId, page);
}
}
}
@Override
public void unbind(final String sessionId) {
cache.remove(sessionId);
}
@Override
public Serializable prepareForSerialization(String sessionId, Object page) {
return null;
}
@Override
public Object restoreAfterSerialization(Serializable serializable) {
return null;
}
@Override
public IManageablePage convertToPage(final Object page) {
return (IManageablePage) page;
}
@Nullable
private Map getSessionCache(final String sessionId) {
return cache.get(sessionId);
}
@Nonnull
private CustomLinkedHashMap getOrCreateSessionCache(final String sessionId) {
return cache.computeIfAbsent(sessionId, s -> new CustomLinkedHashMap<>());
}
/** Mimics "least recently inserted" cache */
private static class CustomLinkedHashMap extends LinkedHashMap {
/** use this parameter to control memory consumption and frequency of appearance of PageExpiredException */
private static final int MAX_PAGES_PER_SESSION = 5;
@Override
protected boolean removeEldestEntry(final Map.Entry eldest) {
return size() > MAX_PAGES_PER_SESSION;
}
}
}