Use of Timer in an asynchronous call in GWT

The following example illustrates the use of a timer that emulates synchronization on an asynchronous RPC call.

The client side waits till an RPC call returns by using the timer.
The code follows for the gwt.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='JSNITest'>
  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>
 
  <inherits name='com.google.gwt.user.theme.standard.Standard'/>
 
  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.mattiz.jsni.client.entrypoint.HelloConnector'/>
   <script src="./js-graph-it.js">
    <![CDATA[
      if ($wnd.$) {
        return true;
      }
      else {
        return false;
      }
    ]]>
    </script>
</module>

For illustrating the concept I have used a js snippet from sourceforge that draws linked labels to form a graph.
The js and css for this can be obtained from http://sourceforge.net/projects/js-graph-it/
The css file and js file can be downloaded from here.

The entrypoint class below:

package com.mattiz.jsni.client.entrypoint;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.mattiz.jsni.client.model.GraphObject;
import com.mattiz.jsni.client.service.JsniCallback;
import com.mattiz.jsni.client.service.JsniService;
import com.mattiz.jsni.client.service.JsniServiceAsync;

public class HelloConnector implements EntryPoint {

	public void onModuleLoad() {
		Label activeLabel = new Label();
		activeLabel.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				System.out.println(event.getNativeButton());
				System.out.println("You clicked!");
			}
		});
		StringBuffer html = new StringBuffer();
		JsniServiceAsync service = (JsniServiceAsync) GWT
				.create(JsniService.class);
		ServiceDefTarget serviceDef = (ServiceDefTarget) service;
		serviceDef.setServiceEntryPoint(GWT.getModuleBaseURL() + "userService");
		final JsniCallback jsniCallback = new JsniCallback(html, activeLabel);
		service.getGraphObjectList(jsniCallback);
		Timer t = new Timer() {
			public void run() {
				if (jsniCallback.getHtml() != null
						&& jsniCallback.getHtml().length() > 0) {
					RootPanel.get().add(
							new HTML(jsniCallback.getHtml().toString()));
					cancel();
					loadGraph();
				}
			}
		};
		t.schedule(5000);
	}

	private static native void loadGraph()/*-{
		$wnd.initPageObjects();
	}-*/;
}

The callback class:

package com.mattiz.jsni.client.service;

import java.util.List;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Label;
import com.mattiz.jsni.client.model.GraphObject;

public class JsniCallback implements AsyncCallback<List<GraphObject>> {

	private StringBuffer html;

	public StringBuffer getHtml() {
		return html;
	}

	public void setHtml(StringBuffer html) {
		this.html = html;
	}

	public JsniCallback(StringBuffer html, Label activeLabel) {
		this.html = html;
	}

	public void onFailure(Throwable caught) {
		Window.alert(caught.getMessage());
	}

 public void onSuccess(List<GraphObject> result) {
        List<GraphObject> graphObjects = result;
		int i = 0;
		String concatenatedHtml = "";
		String connector = "";
		for (GraphObject graphObject : graphObjects) {
			Label label = new Label();
			label.setText(graphObject.getBlockName());
			concatenatedHtml += generateLabelHtml(graphObject, label);
			if (i > 0) {
				connector = generateConnectorHtml(graphObject,
						graphObject.getParentGraphObject());
				concatenatedHtml += connector;
			}
			i++;
		}
		html.append("<div class='canvas' id='mainCanvas'  style='width: 1500px; height: 650px; "
                + "border: 1px solid black;'>" + concatenatedHtml + "</div>");
        setHtml(html);
	}

	private String generateLabelHtml(GraphObject graphObject, Label label) {
		 return "<h1 class='block draggable' id='" + graphObject.getBlockName()
                + "'  style='left: " + graphObject.getInitialPos() + "px; top:"
                + graphObject.getInitialPos() + "px;'>" + label + "</h1>";
	}

	private String generateConnectorHtml(GraphObject parentGraphObject,
			GraphObject graphObject) {
		return "<div class='connector " + parentGraphObject.getBlockName()
				+ " " + graphObject.getBlockName() + "'></div>";
	}
}

The service and async service class:

package com.mattiz.jsni.client.service;

import java.util.List;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.mattiz.jsni.client.model.GraphObject;

@RemoteServiceRelativePath("userService")
public interface JsniService extends RemoteService {

	public List<GraphObject> getGraphObjectList();
}
package com.mattiz.jsni.client.service;

import java.util.List;

import com.google.gwt.user.client.rpc.AsyncCallback;
import com.mattiz.jsni.client.model.GraphObject;


public interface JsniServiceAsync {

	void getGraphObjectList(AsyncCallback<List<GraphObject>> callback);
}

The server side class:

package com.mattiz.jsni.server;
 
import java.util.ArrayList;
import java.util.List;
 
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.mattiz.jsni.client.model.GraphObject;
import com.mattiz.jsni.client.service.JsniService;
 
public class JsniServiceImpl extends RemoteServiceServlet implements
        JsniService {
 
    /**
     * 
     */
    private static final long serialVersionUID = -8780636846638058183L;
 
    public List<GraphObject> getGraphObjectList() {
        int initialPos = 0;
        GraphObject parentGraphObject = null;
        List<GraphObject> graphObjects = new ArrayList<GraphObject>();
        for (int i = 0; i < 6; i++) {
            GraphObject graphObject = new GraphObject();
            graphObject.setBlockName("h" + (i + 1) + "_block");
            graphObject.setInitialPos(initialPos);
            initialPos += 100;
            if (i > 0) {
                graphObject.setParentGraphObject(parentGraphObject);
            }
            graphObjects.add(graphObject);
            parentGraphObject = graphObject;            
        }
        return graphObjects;
    }
 
}

The model class that represents each node of the graph:

package com.mattiz.jsni.client.model;

import java.io.Serializable;

public class GraphObject implements Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = 8456420877276927717L;
	private int initialPos;
	private String connector;
	private String concatenatedHtml;
	private String blockName;
	private GraphObject parentGraphObject;


	public GraphObject getParentGraphObject() {
		return parentGraphObject;
	}
	public void setParentGraphObject(GraphObject parentGraphObject) {
		this.parentGraphObject = parentGraphObject;
	}
	public int getInitialPos() {
		return initialPos;
	}
	public void setInitialPos(int initialPos) {
		this.initialPos = initialPos;
	}
	public String getConnector() {
		return connector;
	}
	public void setConnector(String connector) {
		this.connector = connector;
	}
	public String getConcatenatedHtml() {
		return concatenatedHtml;
	}
	public void setConcatenatedHtml(String concatenatedHtml) {
		this.concatenatedHtml = concatenatedHtml;
	}
	public String getBlockName() {
		return blockName;
	}
	public void setBlockName(String blockName) {
		this.blockName = blockName;
	}
}

JSNITest.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link type="text/css" rel="stylesheet" href="JSNITest.css">
    <link type="text/css" rel="stylesheet" href="js-graph-it.css"/>
    <title>My First GWT application</title>
    <script type="text/javascript" language="javascript" src="jsnitest/JSNITest.nocache.js"></script>
    <script type="text/javascript" language="javascript" src="jsnitest/js-graph-it.js"></script>
    <style>
      .canvas {
        font-family: tahoma;
      }
      .block {
        position: absolute;
        border: 1px solid #7DAB76;
        background-color: #BAFFB0;
        padding: 3px;
      }
      .connector {
        border: 1px solid #7DAB76;
        background-color: #FF9900;
      }
    </style>
   </head>
 
  <body>
 
  </body>
</html>

JSNITest.css

/** Add css rules here for your application. */


/** Example rules used by the template application (remove for your app) */
h1 {
  font-size: 2em;
  font-weight: bold;
  color: #777777;
  margin: 40px 0px 70px;
  text-align: center;
}

.sendButton {
  display: block;
  font-size: 16pt;
}

js-graph-it.css

.draggable
{
	position: absolute;
	cursor: move;
	z-index: 1;
}

.connector
{
	background-color: black;
}

.dock_point
{
	height: 1px;
	width: 1px;
	overflow: hidden;
	padding: 0px !important;
	border: none !important;
	margin: 0px !important;
	position: absolute;
	font-size: 1px;
	visibility: hidden;
}


/** Most GWT widgets already have a style name defined */
.gwt-DialogBox {
  width: 400px;
}

.dialogVPanel {
  margin: 5px;
}

.serverResponseLabelError {
  color: red;
}

/** Set ids using widget.getElement().setId("idOfElement") */
#closeButton {
  margin: 15px 6px 6px;
}
.gwt-Label {
	color: #DF0101;
	font: normal 12px tahoma, arial, helvetica, sans-serif;
	border: 1px solid #99bbe8;
	padding: 14px;
}
.canvas-Style {
	width: 350px;
	height: 250px;
	border: 1px solid black;
}