Hi, all,
Hi, Mone.
I successfully integrated lightstreamer with (smart) gwt. It is just one native js method. Here is a simple example of usage:
package ls.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.ui.RootPanel;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.layout.VLayout;
public class GwtLSIntegrationTest implements EntryPoint {
public void onModuleLoad() {
final VLayout main = new VLayout();
main.setHeight(600);
main.setWidth(1000);
final ListGrid grid = new ListGrid();
grid.setAutoFetchData(true);
grid.setHeight100();
grid.setWidth100();
final ListGridField field1 = new ListGridField("message", "message");
final ListGridField field2 = new ListGridField("timestamp", "timestamp");
grid.setFields(field1, field2);
main.addMember(grid);
// init
final ListGridRecord record = new ListGridRecord();
record.setAttribute("message", "loading...");
record.setAttribute("timestamp", "");
grid.addData(record);
final int index = grid.getRecordIndex(record);
RootPanel.get("nameFieldContainer").add(main);
final Button button = new Button("Start");
init(grid, record.getJsObj(), index);
button.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
SC.say(grid.getSelectedRecord().getAttributeAsString("message") + " " + grid.getSelectedRecord().getAttributeAsString("timestamp"));
}
});
main.addMember(button);
main.draw();
}
private static native void init(ListGrid grid, JavaScriptObject record, int index) /*-{
try {
var page = new $wnd.PushPage();
// localhost is mapped to my ip
page.context.setDomain("localhost");
page.onEngineCreation = function(engine) {
engine.connection.setLSHost("localhost");
// the ls port
engine.connection.setLSPort(8888);
engine.connection.setAdapterName("HELLOWORLD");
engine.changeStatus("STREAMING");
}
page.bind();
page.createEngine("HelloWorldApp", "LS/", "SHARE_SESSION");
var schema = new Array("message","timestamp");
var group = new Array("greetings");
var nvt = new $wnd.NonVisualTable(group,schema,"MERGE");
nvt.setSnapshotRequired(true);
var c = 1;
nvt.onItemUpdate = function(item, itemUpdate, itemName) {
if (itemUpdate.isValueChanged("message")) {
var msg = itemUpdate.getNewValue("message");
var ts = itemUpdate.getNewValue("timestamp");
record["message"] = msg;
record["timestamp"] = ts;
var self = grid.@com.smartgwt.client.widgets.BaseWidget::getOrCreateJsObj()();
self.refreshRow(index);
}
}
page.addTable(nvt,"hellotable");
} catch(error) {
alert(error);
}
}-*/;
}
The tricky part (for non javascript dev or for me) was $wnd in front of the PushPage and NonVisialTable. If you don't have $wnd you will get PushPage is not defined.
The next tricky thing is the same origin policy. I just added this in my gwt.xml file:
<inherits name="com.google.gwt.core.Core"/>
<add-linker name="xs" />
And at last you must include the 2 ligthstreamer js lib files as external js libs. You may do it in your host page or in the gwt.xml like this:
<script src="LS/lscommons.js"></script>
<script src="LS/lspushpage.js"></script>
the adapter (this code is from Alessandro Alinone's tutorial)
import java.util.*;
import java.io.File;
import com.lightstreamer.interfaces.data.*;
public class HelloWorldDataAdapter implements SmartDataProvider {
private ItemEventListener listener;
private volatile GreetingsThread gt;
public void init(Map params, File configDir) throws DataProviderException {
}
public boolean isSnapshotAvailable(String itemName) throws SubscriptionException {
return false;
}
public void setListener(ItemEventListener listener) {
this.listener = listener;
}
public void subscribe(String itemName, Object itemHandle, boolean needsIterator)
throws SubscriptionException, FailureException {
if (itemName.equals("greetings")) {
gt = new GreetingsThread(itemHandle);
gt.start();
}
}
public void subscribe(String itemName, boolean needsIterator)
throws SubscriptionException, FailureException {
}
public void unsubscribe(String itemName) throws SubscriptionException,
FailureException {
if (itemName.equals("greetings") && gt != null) {
gt.go = false;
}
}
class GreetingsThread extends Thread {
private final Object itemHandle;
public volatile boolean go = true;
public GreetingsThread(Object itemHandle) {
this.itemHandle = itemHandle;
}
public void run() {
int c = 0;
Random rand = new Random();
while(go) {
Map<String, String> data = new HashMap<String, String>();
data.put("message", c % 2 == 0 ? "Hello" : "World");
data.put("timestamp", new Date().toString());
listener.smartUpdate(itemHandle, data, false);
c++;
try {
Thread.sleep(1000 + rand.nextInt(2000));
} catch (InterruptedException e) {
}
}
}
}
}
adapters.xml:
<?xml version="1.0"?>
<adapters_conf id="HELLOWORLD">
<metadata_provider>
<adapter_class>com.lightstreamer.adapters.metadata.LiteralBasedProvider</adapter_class>
</metadata_provider>
<data_provider>
<adapter_class>HelloWorldDataAdapter</adapter_class>
</data_provider>
</adapters_conf>
I will create some generic widget that wraps this native code.
Hope this helps someone. :Smile_Ab:
Regards.