Lukasz! Thank you for the link and for your suggestion.
I have implemented a singleton hashmap that stores the UIs of the VaadinSession mapping the session Id to the Collection:
public class VaadinSessionUIsMapper {
/**
* @var HashMap<String, Collection<UI>> The map that maps Vaadin session ids to the corresponding UIs
*/
private HashMap<String, Collection<UI>> sessionUIMap;
/**
* @var VaadinSessionUIsMapper The singleton instance
*/
private static VaadinSessionUIsMapper instance;
/**
* Constructs a new VaadinSessionUIsMapper object
*/
private VaadinSessionUIsMapper() {
String session = VaadinSession.getCurrent().getSession().getId();
Collection<UI> uis = new ArrayList<UI>();
this.sessionUIMap = new HashMap<String, Collection<UI>>();
this.sessionUIMap.put(session, uis);
}
/**
* Gets a singleton instance of this mapper
*
* @return VaadinSessionUIsMapper The mapper
*/
public static VaadinSessionUIsMapper getInstance() {
if (instance == null) {
instance = new VaadinSessionUIsMapper();
}
return instance;
}
/**
* Associate a given Vaadin session to the given UI. If the same UI already existed inside the map,
* the old UI is replaced with the new
*
* @param sessId {@link String} The session id
* @param ui {@link UI} the ui to associate
*
*/
public void putUI(String sessId, UI ui) {
Collection<UI> cuis = this.getUIs(sessId);
if (cuis.contains(ui)) {
for (UI cui : cuis) {
if (cui.getClass().getName().equals(ui.getClass().getName())) {
cuis.remove(cui);
cuis.add(ui);
}
}
}
else {
cuis.add(ui);
}
}
/**
* Associates the given Vaadin session to the given UI collection. If the mapping contained a previous
* collection for the given Vaadin key, the old collection is replaced.
*
* @param sessId {@link String} The session id
* @param uis {@link Collection}<UI> The collection of UI to associate to the session id
*/
public void putUIs(String sessId, Collection<UI> uis) {
this.sessionUIMap.put(sessId, uis);
}
/**
* Gets a collection of Vaadin UIs belonging to the given Vaadin Session
*
* @param session {@link String} The Vaadin session id
* @return Collection<UI> The UI collection
*/
public Collection<UI> getUIs(String sessId) {
return this.sessionUIMap.get(sessId);
}
}
Then I have created a BaseUI class which initializes the Singleton inside the init(VaadinRequest request) method. All the UIs know inherit this UI and when they override it, they call the super.init() at the beginning:
@Push
public class BaseUI extends UI {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void init(VaadinRequest r) {
String sessionId = VaadinSession.getCurrent().getSession().getId();
VaadinSessionUIsMapper.getInstance().putUI(sessionId, this);
}
}
And a UI know looks like:
@SuppressWarnings("serial")
@Push
public class MyPushyUI extends BaseUI {
@WebServlet(value = {"/MyPushyUI/*"}, asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = MyPushyUI.class)
public static class Servlet extends VaadinServlet {
}
@Override
protected void init(VaadinRequest request) {
super.init(request);
setContent(new Button("Logout", event -> {// Java 8
Collection<UI> uis = VaadinSession.getCurrent().getUIs();
System.out.println(uis.toString());
Logger.getLogger("LOGGER").log(Level.ALL, uis.toString());
Collection<UI> mappedUIs = VaadinSessionUIsMapper.getInstance().getUIs(VaadinSession.getCurrent().getSession().getId());
for (UI ui: mappedUIs) {
ui.access(() -> { // Runnable implementation with a lambda expression
// Redirect from the page
System.out.println("UI class = " + ui.getClass().toString());
ui.getPage().setLocation("https://vaadin.com/forum");
ui.push();
});
}
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
getSession().close();
}));
}
}
It works for all the UIs, but just for the very first session, then if I try to repeat the procedure and I click the “Logout” button I get a UIDetachedException:
Dec 09, 2014 3:05:52 PM com.vaadin.server.DefaultErrorHandler doDefault
SEVERE:
com.vaadin.ui.UIDetachedException
at com.vaadin.ui.UI.access(UI.java:1397)
at com.example.application_lifecycle_chapter_4_7.MyPushyUI.lambda$0(MyPushyUI.java:38)
at com.example.application_lifecycle_chapter_4_7.MyPushyUI$$Lambda$3/717438296.buttonClick(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:508)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:198)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:161)
at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:979)
at com.vaadin.ui.Button.fireClick(Button.java:393)
at com.vaadin.ui.Button$1.click(Button.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:168)
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:118)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:287)
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:180)
at com.vaadin.server.communication.PushHandler$3.run(PushHandler.java:174)
at com.vaadin.server.communication.PushHandler.callWithUi(PushHandler.java:253)
at com.vaadin.server.communication.PushHandler.access$200(PushHandler.java:56)
at com.vaadin.server.communication.PushHandler$1.onRequest(PushHandler.java:76)
at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:174)
at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:95)
at org.atmosphere.container.Servlet30CometSupport.service(Servlet30CometSupport.java:66)
at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:1802)
at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:432)
at org.atmosphere.websocket.DefaultWebSocketProcessor$2.run(DefaultWebSocketProcessor.java:285)
at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101)
at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:280)
at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:303)
at org.atmosphere.container.JSR356Endpoint$1.onMessage(JSR356Endpoint.java:177)
at org.atmosphere.container.JSR356Endpoint$1.onMessage(JSR356Endpoint.java:174)
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393)
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:194)
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:95)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:653)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Also if I open the example app inside another browser, I get a null pointer exception, complaining about the singleton’s Collection being empty…:
Dec 09, 2014 3:10:01 PM com.vaadin.server.DefaultErrorHandler doDefault
SEVERE:
java.lang.NullPointerException
at com.example.application_lifecycle_chapter_4_7.VaadinSessionUIsMapper.putUI(VaadinSessionUIsMapper.java:55)
at com.example.application_lifecycle_chapter_4_7.BaseUI.init(BaseUI.java:19)
at com.example.application_lifecycle_chapter_4_7.MyPushyUI.init(MyPushyUI.java:28)
at com.vaadin.ui.UI.doInit(UI.java:645)
at com.vaadin.server.communication.UIInitHandler.getBrowserDetailsUI(UIInitHandler.java:222)
at com.vaadin.server.communication.UIInitHandler.synchronizedHandleRequest(UIInitHandler.java:74)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:41)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1406)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:305)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
How can I handle this exceptions?