Saturday, February 28, 2009

reverse GWT via DWR

This is how I've set upDWR3 to push data out to GWT 1.6. GWT1.6 is needed for the new project structure and DWR3 has json support. Both of these simplify matters greatly.

I was only able to get reverse ajax running by using techniques described in using GWT for mashups. Otherwise, GWT wasn't finding dwr even though the scripts were loaded in the main html page. This is likely due to
GWT application code being loaded in a hidden iframe.

Working from the javascript-chat example (reverse ajax) in DWR3, I modified the sample to return JSON.

public void addMessage(String text, final String callback) {


if (text != null && text.trim().length() > 0) {
messages.addFirst(new Message(text));
while (messages.size() > 10) {
messages.removeLast();
}
}

Browser.withCurrentPage(new Runnable() {
String s;
public void run() {
try {
s=JsonUtil.toJson(messages) ;
} catch (IOException e) {

e.printStackTrace();
}

ScriptSessions.addFunctionCall(callback, s);

}
});
}


Then in my onModuleLoad method for GWT, I set up DWR to load in an Iframe:

    public void onModuleLoad() {

// callbackName = reserveCallback();
callbackName = "chatGroup1";
Log.info("onModuleLoad callbackName: " + callbackName);
addDWRScripts("/reverseGWT/dwr/engine.js");
addDWRScripts("/reverseGWT/dwr/util.js");
addDWRScripts("/reverseGWT/dwr/interface/JavascriptChat.js");
setActiveReverseAjax();
setupChat(this, callbackName);
//Log.info(" setupChat: finshed");
setupChatBox(callbackName);

}



public native void addDWRScripts(String url) /*-{

var elem = document.createElement("script");
elem.setAttribute("language", "JavaScript");
elem.setAttribute("src", url);
document.getElementsByTagName("body")[0].appendChild(elem);

}-*/;


public native void setActiveReverseAjax() /*-{

try{
// a delay is needed or dwr won't have been set up properly when this is called
setTimeout("dwr.engine.setActiveReverseAjax(true)",2500);

} catch(err){
alert("setActiveReverseAjax failed :YOU WILL not be receiving pushed updates from the server though you may be able to send data and receive updates only just after data is sent. You can try increasing the delay in setActiveReverseAjax() in SampleChat.java --> Reason is: "+err );

}
}-*/;




To send a message, I hookup up a button listener to call DWR via JSNI.

Button b = new Button();

b.addListener(Events.OnClick, new Listener<BaseEvent>() {
public void handleEvent(BaseEvent be) {

addMessageScript(text.getValue(), callbackName);

}

});


    public native void addMessageScript(String text, String callbackName) /*-{

try{
//this is the call to DWR set up by addDWRScripts("/reverseGWT/dwr/interface/JavascriptChat.js");
// this results in a call to the addMessage(String text, final String callback) method in JavascriptChat.java

JavascriptChat.addMessage(text,callbackName);

}catch(err){
alert("addMessageScript err: "+err);
}
}-*/;


A JavaScript function has already been set up in the GWT onModuleLoad() method as well which will take the JSON formatted String that is returned from DWR and pass it into my GWT code.

    public native static void setupChat(SampleChat sc, String callback) /*-{

window[callback] = function(someData) {//Ljava/lang/String;
sc.@com.sample.gwt.client.SampleChat::gwtChat(Ljava/lang/String;)(someData);
// sc.@com.sample.gwt.client.SampleChat::gwtChat(Lcom/google/gwt/core/client/JavaScriptObject;)(someData);
}


}-*/;



From there, the JSON formatted String is parsed and the message retrieved:

    public void gwtChat(String jss) {
String s = jss;

JSONObject json = (JSONObject) JSONParser.parse(jss);

Label l = new Label();

try {
s = json.isObject().get("reply").isArray().get(0).isObject().get("text").isString().stringValue();

} catch (Exception e) {

e.printStackTrace();
}


Now data is being pushed from the server when other users enter a message, and you can set up your GWT client to display this pushed data how you'd like.


Notes:
Source code for this example is at reverseGWT . A deployable .war is included. To build from src, please modify build.xml to include:

<pathelement location="/your-path/gwt-user.jar" />
<pathelement location="/your-path/gwt-dev-mac.jar" />



The example is set up using GXT and gwt-log . The example really doesn't depend on using GXT in any way, and straight GWT would be fine. I just happened to be using it and so have set it up that way. Please consult the GXT, gwt-log, DWR and GWT sites for license information. This is just a proof of concept and not intended to be distributed as a usable product.

The chat example from DWR isn't necessarily thread safe as written and should probably use something from java.util.concurrent to handle the messages but this is more a post on configuration than setting up a fully functional chat system.



Followers