BeanItemContainer item added but not displaying

Hi am having a few troubles updating a container from another thread using Vaadin 7.

The purpose is to capture log4j LoggingEvent and write them to a table.

I can see the container is growing in size at the line
logsContainer.addItem(loggingEvent);
But the table does not get updated.

Any help much apprecaited.

The full code of this issue is:

public class LoggingConsoleWindow extends UI {
    private static final long                        serialVersionUID    = 1L;
    private static Logger                            logger                = Logger.getLogger(LoggingConsoleWindow.class);
    private static final String                        LOG_CONSOLE_TITLE    = "Log console";
    private static BeanItemContainer<LoggingEvent>    logsContainer;
    private Table                                    logsTable;

    public LoggingConsoleWindow() {}

    @Override
    protected void init(VaadinRequest request) {
        getCurrent().getPage().setTitle(LOG_CONSOLE_TITLE);
        VerticalLayout content = new VerticalLayout();
        logsTable = new Table();
        logsContainer = new BeanItemContainer<LoggingEvent>(LoggingEvent.class);
        logsTable.setContainerDataSource(logsContainer);
        logsTable.setSizeFull();
        content.addComponent(logsTable);
        content.setSizeFull();
        content.setComponentAlignment(logsTable, Alignment.MIDDLE_CENTER);
        ConsoleAppender consoleAppender = new ConsoleAppender();
        Logger.getRootLogger().addAppender(consoleAppender);
        setContent(content);
        new LogTest().start();
    }

    class LogTest extends Thread {
        AtomicInteger    count    = new AtomicInteger(0);

        @Override
        public void run() {
            while(true){
                try{
                    this.interrupt();
                    logger.warn("A simple log message" + count.incrementAndGet());
                    Thread.sleep(250);
                }catch(InterruptedException e){
                    logger.error(e);
                }
            }
        }
    }

    class ConsoleAppender extends AppenderSkeleton implements Serializable {
        private static final long    serialVersionUID    = 1L;

        @Override
        protected void append(final LoggingEvent loggingEvent) {
            UI.getCurrent().access(new Runnable() {
                @Override
                public void run() {
                    logsContainer.addItem(loggingEvent);
logsTable.refreshRowCache();
                }
            });
        }

        @Override
        public void close() {}

        @Override
        public boolean requiresLayout() {
            return false;
        }
    }
}

Try to call
refreshRowCache()
on your table after adding an item.

Thanks for the quick response Agata. I tried

logsTable.refreshRowCache();

as suggested but still the table is not updated. Updated the code in the post to reflect this change.

Hi, I’m pretty sure the server-side Table is actually updated appropriately; the problem is that there’s no way to communicate those changes to the user’s browser. HTTP works by server responding to client requests, and it is not possible for the server to send anything to the client unless the latter first makes a request. You have to enable either polling (UI.setPollInterval) or server push (easiest to use the @Push annotation in your UI). You shouldn’t need the refreshRowCache line.

Also, if you’re not already aware of it (seeing it’s just a test) please note that your code is going to break the moment more than one browser window is opened (either by the same user or another) because the logsContainer field is static and thus shared but reinitialized in each UI init, plus it’s not properly synchronized between different sessions (the UI.access pattern only synchronizes accesses to a single session).

Amazing. Thanks so much Johannes. The code which finally did the trick was:

@Theme("smartt")
public class LoggingConsoleWindow extends UI {
    private static final long                serialVersionUID    = 1L;
    private static Logger                    logger                = Logger.getLogger(LoggingConsoleWindow.class);
    private static final String                LOG_CONSOLE_TITLE    = "Log console";
    private BeanItemContainer<LoggingEvent>    logsContainer;

    public LoggingConsoleWindow() {}

    @Override
    protected void init(VaadinRequest request) {
        setPollInterval(1000);
        getCurrent().getPage().setTitle(LOG_CONSOLE_TITLE);
        VerticalLayout content = new VerticalLayout();
        Table logsTable = new Table();
        logsContainer = new BeanItemContainer<LoggingEvent>(LoggingEvent.class);
        logsTable.setContainerDataSource(logsContainer);
        logsTable.setSizeFull();
        content.addComponent(logsTable);
        content.setSizeFull();
        content.setComponentAlignment(logsTable, Alignment.MIDDLE_CENTER);
        ConsoleAppender consoleAppender = new ConsoleAppender();
        Logger.getRootLogger().addAppender(consoleAppender);
        setContent(content);
        new LogTest().start();
    }

    class LogTest extends Thread {
        AtomicInteger    count    = new AtomicInteger(0);

        @Override
        public void run() {
            while(true){
                try{
                    logger.warn("A simple log message" + count.incrementAndGet());
                    Thread.sleep(250);
                }catch(InterruptedException e){
                    logger.error(e);
                }
            }
        }
    }

    class ConsoleAppender extends AppenderSkeleton implements Serializable {
        private static final long    serialVersionUID    = 1L;

        @Override
        protected void append(final LoggingEvent loggingEvent) {
            UI.getCurrent().access(new Runnable() {
                @Override
                public void run() {
                    logsContainer.addItem(loggingEvent);
                }
            });
        }

        @Override
        public void close() {}

        @Override
        public boolean requiresLayout() {
            return false;
        }
    }
}

Thanks for the note on static. It was me playing around trying to get it to work.