server push in itmill 5 ?

Hi, In wondering is any kind of server push available in itmill ?

For instance, if I need to periodially get a new datasource from server and update table and various labels accordingly ?

So far I found that ProgressIndicator capable of polling server and acquire its current progress value, but how can I implement the similar for tables, for instance ?

Regards,
Dmitri

If you use progress indicator for polling, any other changes done on the server-side are automatically transferred also. So if you modify your table, these changes are automatically sent to client also.

Currently no real cometd style push is supported.

  • Joonas

Thanks a lot !

So if I’ll put invisible progress indicator for such polling, this will work fine, right ?

Regards,
Dmitri

Probably not as invisible, but as visible yes.

We are planning to include “setPollingFrequency(milliseconds)” type of API to Window, but this did not make itself to 5.0.0. Meanwhile you could use progress indicator or create a polling widget of your own by cut and pasting from progress indicator. In principle, it should be as simple as calling ApplicationConnection.sendPendingVariableChanges() in a timer-loop.

Yes, but you should set it invisible from CSS, because setting it invisible with
setVisible(false)
would remove it from the client-side altogether and the polling would not work.

Below is an example for a somewhat different case, where the value of a component gets updated in another thread.

   void example_ProgressIndicator(Window main, String param) {
        // Create the indicator
        final ProgressIndicator indicator = new ProgressIndicator(new Float(0.0));
        main.addComponent(indicator);
        
        // Set polling frequency to 0.5 seconds.
        indicator.setPollingInterval(1000);
        
        indicator.addStyleName("invisible");
        final Label text = new Label("-- Not running --");
        main.addComponent(text);
        
        // Add a button to start the progress
        final Button button = new Button("Click to start");
        main.addComponent(button);

        // Another thread to do some work
        class WorkThread extends Thread {
            public void run () {
                double current = 0.0;
                while (true) {
                    // Do some "work"
                    try {
                        sleep(50); // Sleep for 50 milliseconds
                    } catch (InterruptedException e) {}
                    
                    current += 0.01;
                    text.setValue("Current: "+current);
                }
            }
        }
        
        // Clicking the button creates and runs a work thread
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                final WorkThread thread = new WorkThread();
                thread.start();
                
                // The button hides until the work is done.
                button.setVisible(false);
            }
        });
    }

And in
styles.css
for the theme set:

.i-progressindicator-invisible {
	display: none;
}

Trying to think about use cases for polling, I wrote this little 66-line chat program. (You need at least two separate machines or different browsers to chat.) This assumes that the servlet container runs the user sessions in different threads, not processes. Well, it works with Tomcat at least. There are some other problems with this as well, but well, it’s just a test.

[code]

import java.util.;
import com.itmill.toolkit.Application;
import com.itmill.toolkit.ui.
;
import com.itmill.toolkit.ui.Button.ClickEvent;

public class ChatApplication extends Application implements Button.ClickListener {
/* ChatApplication instances of different users.
* Warning: a hack, not safe, because sessions can expire. */
static List users = new ArrayList();

/* Messages as a shared list. */
static List messages  = new ArrayList();
int         localSize = 0;

/* User interface. */
Table       messageTable = new Table();
TextField   username     = new TextField("Username:");
TextField   message      = new TextField("Message:");

public void init() {
    final Window main = new Window ("Chat");
    setMainWindow(main);
    setTheme("tests-magi");
    users.add(this);

    main.addComponent(username);

    main.addComponent(messageTable);
    messageTable.addContainerProperty("Sender", String.class, "");
    messageTable.addContainerProperty("Message", String.class, "");
    updateTable();
    
    main.addComponent(message);
    
    Button send = new Button("Send");
    send.addListener(this);
    main.addComponent(send);

    // Poll for new messages once a second.
    ProgressIndicator poller = new ProgressIndicator();
    poller.addStyleName("invisible");
    main.addComponent(poller);
}

public void buttonClick(ClickEvent event) {
    synchronized(users) {
        // Create the new message in the shared list.
        messages.add(new String[]{new String((String) username.getValue()),
                                  new String((String) message.getValue())});

        // Update the message tables for all users.
        for (Iterator i = users.iterator();i.hasNext();) 
            ((ChatApplication)i.next()).updateTable();
    }
}

void updateTable() {
    if (localSize == messages.size())
        return; // No updating needed

    // Add new messages to the table
    while (localSize &lt messages.size())
        messageTable.addItem((Object[])messages.get(localSize++),
                             new Integer(localSize-1));
}

}
[/code] The
ProgressIndicator
is made invisible with the same CSS as above.

Oh, I noticed a problem with the ProgressIndicator; when the application is recompiled, a new notification error box will pop up at every poll, which for some reason slows my browser a lot.

Still going through use cases for polling, I wanted to open a second application-level window and update the contents of the main window from input in the second window. Toolkit 5 does not at least yet have a way to update another window when its content changes, but it’s possible to do with polling. And since there isn’t yet an actual polling component, I’m using the ProgressIndicator hack again. I hope that the hack does not have any side-effects.


// Create a table in the main window to hold items added in the second window
final Table table = new Table();
table.setPageLength(5);
table.getSize().setWidth(100, Size.UNITS_PERCENTAGE);
table.addContainerProperty("Name", String.class, "");
main.addComponent(table);

// Create the second window
final Window adderWindow = new Window("Add Items");
adderWindow.setName("win-adder");
main.getApplication().addWindow(adderWindow);

// Create selection component to add items to the table
final NativeSelect select = new NativeSelect("Select item to add");
select.setImmediate(true);
adderWindow.addComponent(select);

// Add some items to the selection
String items[] = new String[]
{"-- Select --", "Mercury", "Venus", 
        "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"};
for (int i=0; i<items.length; i++)
    select.addItem(items[i]
);
select.setNullSelectionItemId(items[0]
);

// When an item is selected, add it to the table in the main window
select.addListener(new ValueChangeListener() {
    public void valueChange(ValueChangeEvent event) {
        // If the selected value is something else but null selection item.
        if (select.getValue() != null) {
            // Add the selected item to the table in the main window
            table.addItem(new Object[]{select.getValue()}, new Integer(table.size()));
        }
    }
});

// Link to open the selection window
Link link = new Link("Click to open second window",
        new ExternalResource(adderWindow.getURL()));
link.setTargetName("_new");
link.setTargetHeight(50);
link.setTargetWidth(200);
link.setTargetBorder(Link.TARGET_BORDER_DEFAULT);
main.addComponent(link);

// Enable polling to display updated content
ProgressIndicator poller = new ProgressIndicator();
poller.addStyleName("invisible");
main.addComponent(poller);

…plus the CSS code to make the progress indicator invisible as above. The result looks like this:


>

Hi,
is there any plans to add server push to itmill? We are now using hidden ProgressIndicator (polls once a second) for this purpose but especially Firefox 3 uses processor too much (1-25%). IE7 uses 0-3%. Firefox also uses memory quite much (at this moment 150MB).

We are also little afraid of hits to the server because our product is going to production quite soon.

Regards
Markus

Don’t know if this helps in any way but I know few people are at the moment thinking server push for chat application. This however is more of community driven so one may not expect strict “deadlines” :slight_smile:

Regarding ProgressIndicator: if FF3 behaviour is radically different to IE7, I’d vote developers give this issue a peek and see what could be done for the FF3 “issue”.

Marc or Matti, can you check this even briefly?

Full-blown cometd support has been in the backlog for a while (actually since we removed cometd support from Toolkit 4):
http://dev.itmill.com/ticket/111
It seems that the recent developments on Jetty and Glassfish would make support feasible (when run with those servers).

In the mean-time, it should be possible to hack simple server-push that only pushes notification “something has changed, please contact us” from server to client. This could be implemented separately from Toolkit internals and could just do “send pending variable changes even though there are none” in the client-side. Couple of things to note:

  • If you are not using jetty/glassfish, it is hard to implement open http connections without allocating one thread per connection
  • IE has limitation of only two http-connections per window per domain. reserving one connection for notification waiting makes parallel loading of css/images/… impossible while UIDL is loading.

One more thing - implementing
reliable
server-push is hard. Using existing implementation, such as Lightstreamer, might be a good idea. Even for “notification-pushing” mentioned above.

For more info, see

We were using Firefox with Firebug and that caused the processor load. Without Firebug IE7 and Firefox 3 seems to cause quite equal load.

  • markus

Yeah, that’s a good point to remember: Firebug can cause quite a bit of overhead and general slowness!

So it seems that polling would be ok for your application?

At this point yes. If there arise some performance problem we have to check this again.

  • markus