Push not working in Vaadin 7.3.6 application

Hi everyone I have tried to implement a simple push application using Vaadin, but it doesn’t work, I am trying to follow the Book of Vaadin, in chapter 4.7 (Application Lifecycle) at the end there’s a push example:

@Push public class MyPushyUI extends UI {     
@Override     
   protected void init(VaadinRequest request) {         
     setContent(new Button("Logout", event -> {// Java 8             
        for (UI ui: VaadinSession.getCurrent().getUIs())                 
          ui.access(() -> {                     // Redirect from the page                     
               ui.getPage().setLocation("/logout.html");                 
          });             
        getSession().close();         
       }));     
    }
 }

I have tried to reproduce that, but it doesn’t work for me: I have two UIs, ApplicationLifecyclceUI and MyPushyUI, both declare the @Push annotation. ivy.xml is set properly with the vaadin-push support:

<!-- Push support -->
<dependency org="com.vaadin" name="vaadin-push" rev="&vaadin.version;" conf="default->default"/>

Not the two classes. First ApplicationLifecycleUI:

@Push // setting this UI as pushable

public class ApplicationLifecycleUI extends UI {




@WebServlet(value = {"/AppLife/*", "/VAADIN/*"}, asyncSupported = true)

@VaadinServletConfiguration(productionMode = false, ui = ApplicationLifecycleUI.class)

public static class Servlet extends VaadinServlet 

                                implements SessionInitListener, SessionDestroyListener, 

                                           BootstrapListener {

        

        // Handling Session Initialization and Destruction

        @Override 

        protected void servletInitialized() throws ServletException {

            super.servletInitialized();

            getService().addSessionInitListener(this);

            getService().addSessionDestroyListener(this);

        }

        

        

        @Override

        public void sessionInit(SessionInitEvent event)

                throws ServiceException {

            // Do session start stuff here

            

            // Adding the bootstrap listener to the Session

            VaadinSession.getCurrent().addBootstrapListener(this);

        }


        @Override

        public void sessionDestroy(SessionDestroyEvent event) {

            // Do session end stuff here

        }







        // Customizing the Loader Page

        @Override

        public void modifyBootstrapFragment(BootstrapFragmentResponse response) {

            

        }







        @Override

        public void modifyBootstrapPage(BootstrapPageResponse response) {

            

        }




    }




@Override

protected void init(VaadinRequest request) {

        final VerticalLayout layout = new VerticalLayout();

        layout.setMargin(true);

        setContent(layout);




        Button button = new Button("Click Me");

        button.addClickListener(new Button.ClickListener() {

            public void buttonClick(ClickEvent event) {

                layout.addComponent(new Label("Thank you for clicking"));

            }

        });

        layout.addComponent(button);

        

        Button logoutButton = new Button("Logout");

        logoutButton.addClickListener(e -> {

            getPage().setLocation("/Application_Lifecycle_Chapter_4.7/VAADIN/logout.html");

            getSession().close();

        });

        // Setting a faster heartbeat

        setPollInterval(3000);

        layout.addComponent(logoutButton);

    }




}

And the MyPushyUI class:

@Push

public class MyPushyUI extends UI {

    

@WebServlet(value = {"/MyPushyUI/*"}, asyncSupported = true)

@VaadinServletConfiguration(productionMode = false, ui = MyPushyUI.class)

public static class Servlet extends VaadinServlet {

        

    }

    

@Override

    protected void init(VaadinRequest request) {

        setContent(new Button("Logout", event -> {// Java 8

            for (UI ui: VaadinSession.getCurrent().getUIs()) {

                ui.access(() -> { // Runnable implementation with a lambda expression

                    // Redirect from the page

                    ui.getPage().setLocation("https://vaadin.com/forum");

                });

            }

            getSession().close();

        }));

    }

}

Why push is not working in my case? What should I do in order to resolve?

Thank you for the attention. Hope for some help!

This happens, because UI.access doesn’t guarantee you synchronized execution. In your example, you have no chance to send push update before killing session. Try to use UI.accessSynchronously instead.

Thank you for your response Lukasz! I have tried to use UI.accessSynchronously, but I get this exception:

Dec 08, 2014 9:08:27 AM com.vaadin.server.communication.PushHandler onThrowable

SEVERE: Exception in push connection

java.io.IOException: AtmosphereResource Cancelled: 183854b4-fae9-419e-996d-0ba9f86bc1a9

    at org.atmosphere.cpr.AtmosphereResponse.validAsyncIOWriter(AtmosphereResponse.java:459)

    at org.atmosphere.cpr.AtmosphereResponse.access$1100(AtmosphereResponse.java:55)

    at org.atmosphere.cpr.AtmosphereResponse$2.write(AtmosphereResponse.java:499)

    at org.atmosphere.handler.AbstractReflectorAtmosphereHandler.onStateChange(AbstractReflectorAtmosphereHandler.java:141)

    at com.vaadin.server.communication.PushHandler$1.onStateChange(PushHandler.java:63)

    at org.atmosphere.cpr.DefaultBroadcaster.invokeOnStateChange(DefaultBroadcaster.java:1018)

    at org.atmosphere.cpr.DefaultBroadcaster.prepareInvokeOnStateChange(DefaultBroadcaster.java:1038)

    at org.atmosphere.cpr.DefaultBroadcaster.executeAsyncWrite(DefaultBroadcaster.java:879)

    at org.atmosphere.cpr.DefaultBroadcaster$3.run(DefaultBroadcaster.java:520)

    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)

    at java.util.concurrent.FutureTask.run(FutureTask.java:266)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

    at java.lang.Thread.run(Thread.java:745)




Dec 08, 2014 9:08:28 AM com.vaadin.server.communication.PushHandler disconnect

SEVERE: Could not get UI. This should never happen, except when reloading in Firefox - see http://dev.vaadin.com/ticket/14251

What can I do?

It seems like push stack sends data asynchronously. I know this is not state of the art solution but you can give some time (thread.sleep) before killing session.

Could it be because all the UIs have the

asyncSupported = true

param inside the
@WebServlet
annotation? But they say to enable this in the Book of Vaadin, anyway I have tried to do this:

for (UI ui: uis) {

                ui.accessSynchronously(() -> { // 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");

                });

            }

            try {

                Thread.sleep(4000);

            } catch (Exception e) {

                e.printStackTrace();

            }

            getSession().close();

Anyway it still doesn’t work. I don’t know what to try anymore, should I open a ticket for this? Or is there another possible workaround?

Can you test following code:

for (UI ui: uis) {
                ui.accessSynchronously(() -> { // 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");
                    // force push!
                    ui.push();
                });
            }
            try {
                Thread.sleep(4000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            getSession().close();

No, unfortunately even forcing the push doesn’t help, does it works for you?

I made example app:
https://github.com/LukaszByczynski/vaadin-layout-issue/tree/push-test
(branch push-test). It’s works even without UI.access. I tested that with tomcat 8.x

I have tried it, but you have only
one
UI in your example, please, try to add another UI and open them both in the browser, then kill the session, in my case this is the problem (only TestUI gets pushed, the other UI is not even returned in the
Collection of getSession().getUIs()
), cause with just one UI even in my case it works.

Ok. I understand what you want. To achive that you should use event bus. One of the best implementation is here:
https://github.com/peholmst/vaadin4spring/tree/master/spring-vaadin/src/main/java/org/vaadin/spring/events

In all UI bind the listener into session scoped eventbus. Then, when you fire event with kill session message, all other uis can be properly shutdown.

Otherwise, if you would like implement following solution without eventbus, you can use “thread safe” hashmap stored in global singleton. Use as key session id, and store all active UI in session as values.

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?

First, remember all code in singleton should be thread safe!

You said that, you had different UIs across user activity (for example: you have one UI for login, second for other activity)? If answer is true, remember to unregister UI from singleton at detach. There is detach listener in UI.

Code in singleton should be thread safe because if not multiple threads could access it concurrently and corrupt its state e.g. if both Threads are writing to the same mapped Collection of a particular session id, or e.g. when a Thread reads a UI item from a Collection mapped by a particular session id and another Thread removes an item from the same collection, am I right?

So a thread safe implementation might look like this (please, correct me whenever I am wrong):


https://github.com/Tonix-Tuft/vaadin-session-uis-mapper

It is just an example, but it worths for me to understand better.

I noticed I try to
unregister UI from singleton at UI.detach()
as you say I actually cannot do that: VaadinSession is already set to null at that point, so I need to do that inside .access() while iterating over the UIs.

I have also noticed this: everytime I reaload the same page (and therefore the same UI), the UI gets re-added to the Collection (how can I control this behaviour so that if a UI is reloaded I actually remove the previous UI and add the new instantiated?) and at the same time if the same UI is opened at the same time in the same browser but in another Tab I would need to add a new UI inside the collection. How could I handle such implementation? I checked the Vaadin docs for UI but didn’t find useful methods I can use to check this conditions (and inside VaadinSessionUIsMapper.putUI, when I check if a UI is already there, I am wrong, cause cuis.contains(ui) always returns false…)

Is there a way to add this last controls? I guess then I will be satisfied… Anyway I would like to thank you again for the links and the attention!