I have just started evaluating Lightstreamer and worked my way through the "HelloWorld" tutorial successfully. Next I wanted to create a simple "Echo" facility just to ensure I understand what is going on. My understanding (could be wrong) is that if I want to send a message from the client and have it echoed back to me, I need to create a metadata adapter to pass the incoming message to my data adapter, which can then echo it back. However, the "notifiyUserMessage" method in my metadata adapter never gets fired - so either I have misunderstood the way I am to do this, or I just have a plain old bug I don't understand.
So, firstly, is my understanding correct? If so, can anyone tell me what I am doing wrong because it is a pretty simple thing.
Here is my metadata code:
public class MetadataAdapter extends LiteralBasedProvider {
private void loadEchoFeed() throws CreditsException {
if (this.echoFeed == null) {
try {
// Get the IMDataAdapter instance to bind it with this
// Metadata Adapter and send instant messages through it
this.echoFeed = EchoDataAdapter.feedMap.get(this.adapterSetId);
} catch (Throwable t) {
// It can happen if the Messenger Data Adapter jar was not even
// included in the Adapter Set lib directory (the Messenger
// Data Adapter could not be included in the Adapter Set as
// well)
logError("EchoDataAdapter class was not loaded: " + t);
throw new CreditsException(0, "No echo feed available",
"No echo feed available");
}
if (this.echoFeed == null) {
// The feed is not yet available on the static map, maybe the
// Echo Data Adapter was not included in the Adapter Set
logError("EchoDataAdapter not found");
throw new CreditsException(0, "No echo feed available",
"No echo feed available");
}
}
}
private void handleEchoMessage(String message) throws CreditsException {
this.echoFeed.sendMessage(message);
}
//------- Public methods--------
public MetadataAdapter() {
}
public void init(Map params, File configDir) throws MetadataProviderException {
super.init(params, configDir);
String logConfig = (String)params.get("log_config");
if (logConfig != null) {
File logConfigFile = new File(configDir, logConfig);
String logRefresh = (String)params.get("log_config_refresh_seconds");
if (logRefresh != null)
DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), Integer.parseInt(logRefresh) * 1000);
else {
DOMConfigurator.configure(logConfigFile.getAbsolutePath());
}
}
this.adapterSetId = ((String)params.get("adapters_conf.id"));
}
public void notifyUserMessage(String user, String session, String message) throws NotificationException, CreditsException {
// Triggered by a client "sendMessage" call.
// The message encodes an instant message from the client.
if (message == null) {
logger.warn("Null message received");
throw new NotificationException("Null message received");
}
// Load the echco feeder
this.loadEchoFeed();
this.handleEchoMessage(message);
}
}
Here is my data adapter code
public class EchoDataAdapter implements SmartDataProvider {
private ItemEventListener listener;
private final ExecutorService executor; //Used to enqueue the calls to the listener.
private Logger logger;
public static final ConcurrentHashMap<String, EchoDataAdapter> feedMap =
new ConcurrentHashMap<String, EchoDataAdapter>();
//------- Private methods--------
//------- Public methods--------
public EchoDataAdapter() {
executor = Executors.newSingleThreadExecutor();
}
public void init(Map params, File configDir) throws DataProviderException {
String logConfig = (String) params.get("log_config");
if (logConfig != null) {
File logConfigFile = new File(configDir, logConfig);
String logRefresh = (String) params.get("log_config_refresh_seconds");
if (logRefresh != null) {
DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), Integer.parseInt(logRefresh) * 1000);
} else {
DOMConfigurator.configure(logConfigFile.getAbsolutePath());
}
}
// Read the Adapter Set name, which is supplied by the Server as a parameter
String adapterSetId = (String) params.get("adapters_conf.id");
// Put a reference to this instance on a static map
// to be read by the Metadata Adapter
feedMap.put(adapterSetId, this);
}
public boolean isSnapshotAvailable(String itemName) throws SubscriptionException {
return false;
}
public void setListener(ItemEventListener listener) {
// We will be passed a reference to a listener that we will use to inject the real-time events
this.listener = listener;
}
public void subscribe(String itemName, Object itemHandle, boolean needsIterator) throws SubscriptionException, FailureException {
// We must be ready to accept subscription requests. If we receive an "echo" item we will start a thread to
// handle the data.
// When the “echo” item is subscribed to by the first user, our Adapter receives that method call and starts a thread
// that will generate the real-time data.
// If more users subscribe to the “echo” item, the subscribe method is not called anymore.
// When the last user unsubscribes from this item, our Adapter is notified through the unsubscribe call
if (itemName.equals("echo")) {
// Nothing to do
}
}
public void subscribe(String itemName, boolean needsIterator) throws SubscriptionException, FailureException {
}
public void unsubscribe(String itemName) throws SubscriptionException, FailureException {
// No more users
if (itemName.equals("echo")) {
// Nothing to do
}
}
public void sendMessage(String message) {
// Receives a message from the metadata adapter, which we will simply echo back
this.echoMessage(message);
}
private void echoMessage(String message) {
final HashMap<String, String> echo = new HashMap<String, String>();
echo.put("message", message);
//If we have a listener create a new Runnable to be used as a task to pass the
//new update to the listener
Runnable echoMessage = new Runnable() {
public void run() {
// call the update on the listener;
// in case the listener has just been detached,
// the listener should detect the case
listener.smartUpdate(listener, echo, false);
}
};
//We add the task on the executor to pass to the listener the actual status
executor.execute(echoMessage);
}
}
and my client just does this
function extractFieldData(event,field) {
var value;
if (event.isValueChanged(field)) {
value = event.getValue(field);
}
return value;
}
function handleEcho(event) {
var eventType = event.item; //This provides the update event name
var echoed=extractFieldData(event,"message");
alert("Echo: "+echoed);
}
var client = new LightstreamerClient("http://rnsdev:8080","RNS");
client.connect();
var echoSub = new Subscription("DISTINCT","echo",new Array("message"));
echoSub.setDataAdapter("ECHO");
echoSub.addListener({
onItemUpdate:handleEcho
});
client.subscribe(echoSub);
client.sendMessage("Will this message get back to me?");