I am currently developing an application which uses the “invisible progress indicator” hack to achieve server push functionality. Is there a way to know when the progress indicator is requesting a repaint? Adding repaint listener to progress indicator does not help, nor does overriding the paintContent method.
The problem is that the content to be pushed is generated in a separate thread, which eventually gets out of sync of the progress indicator’s polling interval. As a result the content is being generated at the same time when the content is being handled in CommunicationManager and this causes the following exception:
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at com.itmill.toolkit.terminal.gwt.server.CommunicationManager.getDirtyVisibleComponents(CommunicationManager.java:1151)
at com.itmill.toolkit.terminal.gwt.server.CommunicationManager.paintAfterVariablechanges(CommunicationManager.java:396)
at com.itmill.toolkit.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:309)
at com.itmill.toolkit.terminal.gwt.server.ApplicationServlet.service(ApplicationServlet.java:445)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:502)
...
How this could be fixed? Some suggestions:
-
Add a possibility to add a listener to ProgressIndicator which would be called when client contacts the server. This may have some performance issues, but typically server-push hacks are used in systems which aren’t meant for large number of users anyway.
-
Make the handling of dirtyPaintabletSet thread-safe in the CommunicationManager class. Actually, I added synchronization blocks to relevant places in CommunicationManager. As the result the exceptions are gone and everything in my application works perfectly.
Example where synchronization is needed in CommunicationManager (line ~1133):
private ArrayList getDirtyVisibleComponents(Window w) {
synchronized (dirtyPaintabletSet) {
final ArrayList resultset = new ArrayList(dirtyPaintabletSet);
...
-Jukka