I'm trying to add Real-Time Messaging to an already large SmartGWT application.
I studied the doc and the examples, and ran one of the examples in a development environment.
We're using GWT 2.6.1 and SmartClient Version: v9.1p_2014-06-04/PowerEdition Deployment (built 2014-06-04) and Eclipse Kepler SR2.
First, I added Real-Time Message handling to the client, with a fair amount of error handling and logging, like so:
In the server code, I inserted this into code that is run often, specifically, the doFilter() method of the filter we use for pretty much everything coming from the server:
When I run it in Eclipse, the 2 messages generated by the server code ("Sending" and "Sent") appear in the Eclipse Console about every 10 seconds, but I don't get anything at all from the client. Regarding setup, I added the 3 RTM JARs to war/WEB-INF/lib, and added them to the build path in Eclipse. I added the following to smartgwt.properties, and verified that the settings are present in the generated server.properties in the WAR (removing comments):
Finally, I un-commented this paragraph in web.xml:
The final clue I have is that the Eclipse Console shows this:
The really curious thing to me is that the GET URL contains a snippet which when URL decoded reads:
This is especially curious considering that, when the client (on exit) does a Messaging.getSubscribedChannels(), it gets "pushMessage" as a subscribed channel.
I presume there's some piece of setup or configuration that is missing here. I did my best to follow the directions in the Messaging PDF and the various README files.
What did I miss?
I studied the doc and the examples, and ran one of the examples in a development environment.
We're using GWT 2.6.1 and SmartClient Version: v9.1p_2014-06-04/PowerEdition Deployment (built 2014-06-04) and Eclipse Kepler SR2.
First, I added Real-Time Message handling to the client, with a fair amount of error handling and logging, like so:
Code:
public class [B]MyApplication [/B]implements EntryPoint
{
@Override
public void onModuleLoad()
{
RPCManager.setShowPrompt(true);
RPCManager.setDefaultTimeout(60000);
// Handle any Real-Time Messages pushed to us from the server.
Messaging.subscribe("pushMessage", new MessagingCallback() {
@Override
public void execute(Object data)
{
System.out.println("");
System.out.println(">>> R E C E I V E D ! ! ! <<<");
System.out.println("");
ClientReceivePushMessage.receiveAndHandle((JavaScriptObject) data);
}
} );
...
// Then, it opens the main window and runs the app.
}
}
public class [B]ClientReceivePushMessage[/B]
{
public static void receiveAndHandle(final JavaScriptObject messageJsObj)
{
// NOTE: this method is static because doing that allows us to have the casting and error handling
// here instead of in the calling method, which is the entry point, so it should be kept simple.
if (messageJsObj != null)
{
final Object messageMap = JSOHelper.convertToJava(messageJsObj);
if (messageMap instanceof Map)
{
@SuppressWarnings("unchecked")
final PushMessage message = new PushMessage((Map<String, String>) messageMap);
switch (message.getMessageType())
{
case ONE_TYPE:
System.out.println(">>> YES!! Message Received of One Type: " + message.getContents());
break;
case ANOTHER_TYPE:
System.out.println(">>> YES!! Message received of Another Type: " + message.getContents());
break;
default:
throw new IllegalArgumentException("PushMessage.receive: unknown MessageType = " + message.getMessageType().toString());
}
}
else
{
String msg = "Object has type " + messageMap.getClass().getName() + ", not PushMessage.";
System.out.println(">>> ERROR: received " + msg);
throw new IllegalArgumentException(msg);
}
}
else
{
String msg = "Real-Time Message Object is null.";
System.out.println(">>> ERROR: received " + msg);
throw new IllegalArgumentException(msg);
}
}
}
public class [B]PushMessage[/B]
{
@SuppressWarnings("unused")
private static final long serialVersionUID = -9184815913070178774L;
private PushMessageType messageType;
private String contents; // This will probably need to get more complex later.
public PushMessage(PushMessageType messageType, String contents)
{
this.messageType = messageType;
this.contents = contents;
}
// These next 2 methods are needed because JSOHelper.convertToJava() can
// only reliably convert collections:
public PushMessage(Map<String, String> map)
{
this.messageType = PushMessageType.valueOf(map.get("MessageType"));
this.contents = map.get("Contents");
}
public Map<String, String> toMap()
{
Map<String, String> map = new HashMap<String, String>();
map.put("PushMessageType", this.messageType.toString());
map.put("Contents", this.contents);
return map;
}
////// getters and setters removed here...
}
public enum [B]PushMessageType [/B]{ ONE_TYPE, ANOTHER_TYPE } // Obviously, these will be replaced.
Code:
...
// Throttle this to once per 10 seconds, at most.
if (System.currentTimeMillis() > whenLastSend + 10000L)
{
ServerPushMessage message = new ServerPushMessage(PushMessageType.ONE_TYPE, "!!! Here !!!");
System.out.println(">>> Sending... <<<");
try
{
message.[I][B]send[/B][/I]("pushMessage");
}
catch(Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
whenLastSend = System.currentTimeMillis();
}
...
public class [B]ServerPushMessage[/B]
{
private PushMessage message;
public ServerPushMessage(PushMessageType messageType, String contents)
{
message = new PushMessage(messageType, contents);
}
public void send(String channel) throws Exception
{
ISCMessageDispatcher dispatcher = ISCMessageDispatcher.instance(); // Use the no-arg version in the server.
dispatcher.[I][B]send[/B][/I](new ISCMessage(channel, message.toMap()));
System.out.println(">>> Sent message: " + this.message.getContents() + " <<<");
}
}
Code:
messaging.keepaliveInterval: 3000
messaging.keepaliveReestablishDelay: 1000
messaging.connectTimeout: 4000
messaging.connectionTTL: 120000
messaging.flushBufferSize: 8096
messaging.dispatcherImplementer: com.isomorphic.messaging.LocalMessageDispatcher
Code:
<servlet>
<servlet-name>MessagingServlet</servlet-name>
<servlet-class>com.isomorphic.messaging.MessagingServlet</servlet-class>
</servlet>
Code:
>>> Sending... <<<
>>> Sent message: !!! Here !!! <<<
[WARN] 404 - GET /triad40/sc/messaging?ts=1446145027750&isc_noLog=1&type=connect&connectionID=isc_HiddenFrame_5&subscribedChannels=%7B%0D%20%20%20%20pushMessage%3A%7B%0D%20%20%20%20%20%20%20%20subscriptionCallback%3Anull%0D%20%20%20%20%7D%0D%7D&eventStream=true (127.0.0.1) 1385 bytes
Request headers
Host: 127.0.0.1:8888
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/event-stream
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1:8888/Triad40.html?gwt.codesvr=127.0.0.1:9997
Cookie: GLog=%7B%0D%20%20%20%20trackRPC%3Afalse%0D%7D; JSESSIONID=lb0o31x93ne91d06fx8hovuhy; isc_cState=ready
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers
Content-Type: text/html;charset=ISO-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1385
[WARN] 404 - GET /triad40/sc/messaging?ts=1446145031767&isc_noLog=1&type=connect&connectionID=isc_HiddenFrame_6&subscribedChannels=%7B%0D%20%20%20%20pushMessage%3A%7B%0D%20%20%20%20%20%20%20%20subscriptionCallback%3Anull%0D%20%20%20%20%7D%0D%7D&eventStream=true (127.0.0.1) 1385 bytes
Request headers
Host: 127.0.0.1:8888
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/26.0
Accept: text/event-stream
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1:8888/Triad40.html?gwt.codesvr=127.0.0.1:9997
Cookie: GLog=%7B%0D%20%20%20%20trackRPC%3Afalse%0D%7D; JSESSIONID=lb0o31x93ne91d06fx8hovuhy; isc_cState=ready
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers
Content-Type: text/html;charset=ISO-8859-1
Cache-Control: must-revalidate,no-cache,no-store
Content-Length: 1385
Code:
subscribedChannels={
pushMessage:{
subscriptionCallback:null
}
}
I presume there's some piece of setup or configuration that is missing here. I did my best to follow the directions in the Messaging PDF and the various README files.
What did I miss?
Comment