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