Global Event Bus ?

262 views
Skip to first unread message

Luis Montes

unread,
Oct 13, 2011, 6:48:35 PM10/13/11
to google-we...@googlegroups.com
I have a use case where I need to compile separate entry points into separate javascript files and one or multiple files arbitrarily on different pages.  This is common with JSR-168 portlets, but plenty of other types of apps might need this.

The problem is that I can't find a mechanism outside of writing JSNI code to a pub/sub system such as this:  https://github.com/phiggins42/bloody-jquery-plugins/blob/master/pubsub.js

I've wrapped that code into a PubSub.java class here:  http://azprogrammer.com/gwt/PubSub.java
That class contains all the JSNI I should need, so I figure if I want say:  application GwtA to communicate with application GwtB I'd have to write JSNI code in those apps to use the Global bus crated by PubSub.  And that works, but I'd rather PubSub was just a utility and have GwtA and GwtB not require subscribing with JSNI.

So I created a Subsciber interface:
public interface Subscriber {
public void handleEvent(String name, Object val);
}





The GwtA & B apps could just:  

PubSub m_pubSub = new PubSub(); 
//send with:
m_pubSub.publish("sendName", "Value from gwtA");

//or subcribe with:
m_pubSub.subscribe("sendName", new Subscriber() {
public void handleEvent(String name, Object val) {
   //do something
}
});



This works fine once the app is compiled.  I can even pub and sub to the event bus with external non-GWT code in the page.
However, it doesn't work in dev mode in eclipse.    I'm sure stuff only working once compiled is a bug, but I can't really wait for this to be fixed.

Is there a better way to achieve Pub/Sub globally on separately compiled GWT apps?  Can whatever mechanism that is be exported to be used by non-GWT code?


Thanks,

Luis Montes



Tomasz Gawel

unread,
Oct 14, 2011, 7:50:21 PM10/14/11
to Google Web Toolkit
If you want to pass objects between to separately compiled gwt modules
via javascript it can only be object that extend JavaScriptObject or
primitives.
but these can also be your custom overlay objects defined on both
sides.
for example when module A knows about
com.google.gwt.core.client.JsDate and module B knows it either they
can pass this object over javascript and "overlay it properly" as
JsDate extends JavaScriptObject, but it is not valid as to "plain java
objects" as they are (or most possibly are) differently compiled on
both sides.
If you need to share a "plain java objects" you can make a JavaScript
wrapper over it and pass the wrapper js object to another module which
can treat it as overlay object - but as you see it is rather a
emergency hack than the solution to be use extensively :).

Tomasz Gawel

unread,
Oct 14, 2011, 7:50:51 PM10/14/11
to Google Web Toolkit
package samples;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsDate;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;

public class JsBus extends JavaScriptObject {

public static class JsHandlerRegistration extends JavaScriptObject
implements HandlerRegistration {
protected JsHandlerRegistration() {}
@Override
public native final void removeHandler() /*-{
this.removeHandler();
}-*/;
}

public static interface Callback {
void call(JavaScriptObject event);
}

public static final native JsBus getInstance() /*-{
var name = "jsBusSingletonInstance";
return $wnd[name] || ($wnd[name] = (function(){
var _h = {};
return {
fire:function(key, evt){
if(_h[key]){
for(var i=0;i<_h[key].length;i++){
try {
_h[key][i](evt);
}
catch(e) {}
}
}
},
addHandler:function(key, handler){
(_h[key] || (_h[key] = [])).push(handler);
return {
removeHandler:function(){
if(_h[key]){
for(var i=_h[key].length-1; i>-1; i--){
if(_h[key][i] === handler){
_h[key].splice(i, 1);
if(_h[key].length == 0){
_h[key] = null;
delete _h[key];
}
return;
}
}
}
}
};
}
}
})());
}-*/;

protected JsBus() {}

public void fire(String key, JSONObject event) {
fire(key, event.getJavaScriptObject());
}

public native void fire(String key, JavaScriptObject event) /*-{
this.fire(key, event);
}-*/;

public native JsHandlerRegistration addHandler(String key, Callback
callback) /*-{
return this.addHandler(key, function(evt){
callback.@samples.JsBus.Callback::call(Lcom/google/gwt/core/client/
JavaScriptObject;)(evt);
});
}-*/;

}

class A implements EntryPoint {

@Override
public void onModuleLoad() {
final JsBus jsBus = JsBus.getInstance();
jsBus.addHandler("timer_in_b", new JsBus.Callback() {

@Override
public void call(JavaScriptObject event) {
Window.alert(event.<JsDate> cast().toLocaleTimeString());
}

});

new Timer() {

@Override
public void run() {
JSONObject event = new JSONObject();
event.put("message", new JSONString("Message from class A!"));
event.put("data", JSONParser
.parseStrict("{\"someData\":[1,2,3]}"));
jsBus.fire("event_from_A", event);
}
}.schedule(10000);
}
}

class B implements EntryPoint {

@Override
public void onModuleLoad() {

final Timer timer = new Timer() {

@Override
public void run() {
JsBus.getInstance().fire("timer_in_b", JsDate.create());
}
};
timer.scheduleRepeating(1500);

JsBus.getInstance().addHandler("event_from_A", new JsBus.Callback()
{

@Override
public void call(JavaScriptObject event) {
timer.cancel();

Window.alert(new JSONObject(event).get("message")
.isString().stringValue());
}
});
}
}

Stefan Ollinger

unread,
Oct 14, 2011, 8:22:10 PM10/14/11
to google-we...@googlegroups.com
Hello,

you could use a common library to define your message classes and import that library in both gwt modules. Then use something like comet to push your messages to the clients: http://code.google.com/p/gwt-comet/

Regards,
Stefan

Stefan Ollinger

unread,
Oct 14, 2011, 8:25:16 PM10/14/11
to google-we...@googlegroups.com
Oh, and if you want to do local communication between separate modules, i would use a JSNI approach and de-/serialize the common message classes. Using the AutoBean framework for example:  http://code.google.com/p/google-web-toolkit/wiki/AutoBean
--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

Luis Montes

unread,
Oct 17, 2011, 11:57:43 AM10/17/11
to google-we...@googlegroups.com
Thanks for the help guys.  I got it working using a modified version Tomasz's implementation.  I think the main difference with mine was that it's only taking JavascriptObject for an event object and that the bus itself is an javascript object.


Luis
Reply all
Reply to author
Forward
0 new messages