Vaadin polling - best practice tutorial processes requesting objects (ui co

I’ve a use-case for the polling functionality in Vaadin. This functionality is basically just an interval configured for the client-side. Every time this interval kicks in, the client asks the server for changes and updates its UI accordingly. I need to use this functionality since I’ve a background task which gathers data for a combobox. However, this combobox isn’t crucial for the app itself, so I decided to let it display “disabled” until the data is collected. However, this works fine but I need to configure polling to automatically update the combobox (or better the UI containing the combobox).

To achieve this I’ve created a polling-manager according to the best-practice tutorial in the [Vaadin-Wiki]
[1]
.

#!java
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

import com.vaadin.ui.UI;

public class UIPollingManager
{

    private Map<UI, Map<Object, Integer>> pollRequests;

    public UIPollingManager()
    {
        pollRequests = new WeakHashMap<>(); // Let's use weak references in case someone forgets to unregister properly
    }

    /**
     * Registers a poll request for the given UI. Sets the pollInterval of this UI to the lowest registered interval.
     * @param ui
     * @param requestor
     * @param pollIntervalInMillis poll interval in milliseconds
     */
    public void registerPollRequest(UI ui, Object requestor, int pollIntervalInMillis)
    {
        Map<Object, Integer> uiRequests = pollRequests.get(ui);
        if (uiRequests == null)
        {
            uiRequests = new HashMap<>();
            pollRequests.put(ui, uiRequests);
        }

        uiRequests.put(requestor, pollIntervalInMillis);

        setPollInterval(ui);
    }

    /**
     * Removes a poll request for the given UI (if existent). Sets the pollInterval of this UI to the lowest registered interval
     * remaining or -1 if no more requests exist for the UI
     * @param ui
     * @param requestor
     */
    public void unregisterPollRequest(UI ui, Object requestor)
    {
        Map<Object, Integer> uiRequests = pollRequests.get(ui);
        if (uiRequests != null)
        {
            uiRequests.remove(requestor);

            // Remove the UI from our map if no requests exist anymore
            if (uiRequests.size() <= 0) pollRequests.remove(ui);
        }

        setPollInterval(ui);
    }

    /**
     * Removes all poll requests of the given UI and sets the pollInterval to -1
     * @param ui
     */
    public void unregisterAllPollRequests(UI ui)
    {
        pollRequests.remove(ui);

        ui.setPollInterval(-1);
    }

    /**
     * Sets the pollInterval of the given UI to the lowest registered interval time of this UI
     * @param ui
     */
    private void setPollInterval(UI ui)
    {
        Map<Object, Integer> uiRequests = pollRequests.get(ui);
        if (uiRequests != null)
        {
            ui.setPollInterval(getLowestNumber(uiRequests.values()));
        }
    }

    /**
     * Returns the lowest number of a given Integer-Collection. Returns -1 if no valid Integer is included in the collection.
     * @param intervalArray
     * @return
     */
    private Integer getLowestNumber(Collection<Integer> intervalArray)
    {
        Integer lowestNum = null;

        for (Integer i : intervalArray)
        {
            if (i != null && ( lowestNum == null || i < lowestNum )) lowestNum = i;
        }

        if (lowestNum == null) return -1;
        else
            return lowestNum;
    }
}

The manager there is basically a collection of UI-components with their needed polling-intervals in milliseconds mapped to them. These components are again in a map associated to their correspondenting UIs. However, as far as I know the only entity concerned about polling is basically the UI itself. Also the code only associates polling intervals to the UIs leaving the component entities (like Buttons, Comboboxes etc.) kind of untouched. It updates the whole UI (so each component contained in the UI) in the given frequency anyway.

Why does the manager still keeps accurately track of components? Wouldn’t it be suitable to just have a collection of intervals mapped to UIs?

Basically instead of a map like this:

private Map<UI, Map<Object, Integer>> pollRequests;

A map like this:

// UI to interval (as Integer) mapping
private Map<UI, Integer> pollRequests;

[1]
: https://vaadin.com/wiki?p_p_id=36&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=row-1&p_p_col_pos=2&p_p_col_count=4&_36_struts_action=%2Fwiki%2Fview&p_r_p_185834411_nodeName=vaadin.com+wiki&p_r_p_185834411_title=Using+polling#section-Using+polling-Polling+for+multiple+components

Dear Kai,

I am not sure what to answer or what exactly the question is.

shrug
–Enver

Dear Enver,

the tutorial keeps track of UI-components and UIs. So let’s say, that we have an UI and a Button. The polling manager receives an UI, the button and an interval as arguments. It checks whether the UI was already saved (another component from the given UI was already added) and sets the interval to the lowest possible. Let’s assume the following scenario:

  • Register UI1, Button1, 3000
  • UI1 get’s updated every 3000 ms
  • Register UI1, Label1, 2000
  • UI1 get’s updated every 2000 ms

You may have already noticed that this whole registration depends only on the UI. Thus the question is,
why the polling manager still keeps track of the components (Button1 and Label1)?
They are not relevant for the code. It would be exactly the same if I do this:

  • Register UI1, 3000
  • UI1 get’s updtated every 3000 ms
  • Register UI1, 2000
  • UI1 get’s updated every 2000 ms

And even if you say that the UI-component arguments are for the developer experience, it would still be better to do something like this:

  • Register Button1, 3000
  • Get the UI of Button1 → UI1
  • Register UI1, 3000
  • UI1 get’s updated every 3000 ms
  • Register Label1, 2000
  • Get the UI of Label 1 → UI1
  • Register UI1, 2000
  • UI1 get’s updated every 2000 ms

This version would be more robust since one can’t provide an UI which is not the UI of the component-argument.

Thanks,
Kai

Thanks, Kai.

We’re currently undergoing restructuring of parts of the website - as you can see the Wiki is write-protected for the time being. I have linked your improvement suggestion to the article you mentioned so this will be picked up by the restructuring team when it comes across it.

Best Regards,
–Enver

There is a bug in the code on here and in the wiki. The last registered poll, once removed, never sets the polling interval back to -1 as the uiRequests in pollRequests.get(ui) will be null, and it is never handled. setPollInterval should be:

private void setPollInterval(UI ui)
    {
        Map<Object, Integer> uiRequests = pollRequests.get(ui);
        if (uiRequests != null)
        {
            ui.setPollInterval(getLowestNumber(uiRequests.values()));
        }else{
            ui.setPollInterval(-1);
        }
    }