Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
detach() event in Listener never called
I have seen some old posts and this link but cannot seem to get the detach() event.
I am using the code below to initialize the servlet params and then build a little UI.
What I was expecting is that if I closed my browser, eventyually after 15 seconds or more, I would get
the detach event triggered, But that does not seem to happen.
I read in other threads that it does not work with @Push or websockets etc. I tried removing @Push but it still does not get called.
Am I doing something wrong ? Or is my assumption that this method should be called when a browser closes incorrect ?
Thanks for any help.
@SuppressWarnings("serial")
@Theme("demo")
@PreserveOnRefresh
@Push(PushMode.AUTOMATIC)
public class DemoUI extends UI {
@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = DemoUI.class, heartbeatInterval=5, closeIdleSessions=true)
public static class Servlet extends VaadinServlet {
}
@Override
protected void init(VaadinRequest request) {
addDetachListener(new DetachListener() {
@Override
public void detach(DetachEvent event) {
System.err.println("Detach Event = "+event.getConnector().getConnectorId());
}
});
// UI Code here
}
}
Some more info :- I am running my code from within Eclipse using Tomcat 7.x (not sure if that makes any difference)
It looks like I do get the events, but only when I open a new browser request after the previous one has expired.
In fact with chrome, I simply need to type http://local and autocomplete brings up the URL (without loading it ) and that causes the old session to detach ..
Is there any way around this ? Ideally I would like the server to detect the loss of hearbeat without having to wait for a new request,
Have you checked if this Add-On actually does what you are trying to do?
https://vaadin.com/directory/#!addon/cleanupservlet-add-on
Tatu Lund: Have you checked if this Add-On actually does what you are trying to do?
https://vaadin.com/directory/#!addon/cleanupservlet-add-on
Well, i try to use minimal count of add-ons.
In this case i create service, that close timeouted UIs and Sessions.
public class VaadinServletWithListeners extends VaadinServlet {
private static ConcurrentHashMap<VaadinSession, Integer> mapVaadinSessionToCodOp = new ConcurrentHashMap<>();
@Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
VaadinService.getCurrent().addSessionInitListener((SessionInitListener) event -> {
VaadinSession session = event.getSession();
mapVaadinSessionToCodOp.put(session, 0);
String remoteAddr = event.getRequest().getRemoteAddr();
});
VaadinService.getCurrent().addSessionDestroyListener((SessionDestroyListener) event -> {
VaadinSession session = event.getSession();
mapVaadinSessionToCodOp.remove(session);
});
}
public static synchronized ConcurrentHashMap<VaadinSession, Integer> getMapVaadinSessionToCodOp(){
return mapVaadinSessionToCodOp;
}
}
public class SessionAndUICloser {
public void closeSessionsAndUIs() {
int defaultHeartbeatInterval = DefaultDeploymentConfiguration.DEFAULT_HEARTBEAT_INTERVAL;
int cleanupIntervalMillis = 3 * 1000 * defaultHeartbeatInterval;
// Close all timeouted UIs and Sessions
ConcurrentHashMap<VaadinSession, Integer> allSessionsWithCodOps = VaadinServletWithListeners.getMapVaadinSessionToCodOp();
Enumeration<VaadinSession> keys = allSessionsWithCodOps.keys();
while (keys.hasMoreElements()){
VaadinSession vaadinSession = keys.nextElement();
Collection<UI> uIs = vaadinSession.getUIs();
boolean hasAliveUIs = false;
for (UI ui : uIs){
if (System.currentTimeMillis() > ui.getLastHeartbeatTimestamp() + cleanupIntervalMillis){
ui.close();
} else {
hasAliveUIs = true;
}
}
if (!hasAliveUIs){
vaadinSession.close();
allSessionsWithCodOps.remove(vaadinSession);
}
}
}
}
SessionAndUICloser starts with SPRING-scheduler with period 60 sec.
Second Integer in Map - it is user id in my purposes.
Maybe this code has some bugs and memory leaks?