package com.smartgwt.client.rpc; import com.smartgwt.client.rpc.RPCCallback; import com.smartgwt.client.util.SC; /** * The Messaging class provides APIs to make use of SmartGWT Real-Time Messaging module, an * optional module available with SmartGWT Power or Enterprise Edition which allows browser based web applications to * publish and subscribe to HTTP Messaging channels, allowing the application to receive (and send) messages * delivered via server push for "real-time" updates from the server without polling. * <P> * To use this class, you will need to inherit <code>RealtimeMessaging</code> or * <code>RealtimeMessagingNoScript</code> from the <code>messaging.jar</code> * (required for client side functionality only), and include the <code>isomorphic_messaging</code> * and <code>isomorphic_js_parser</code> jar files for deployment on the server. * <P> * See the Messaging Quick Reference PDF file for more information on the optional Messaging module. * */ public class Messaging { /** * Set the url of the messaging servlet. * * @param URL May be prefixed with [ISOMORPHIC] to use the isomorphicDir */ public static native void setMessagingURL(String URL) /*-{ if ($wnd.isc.Messaging == null) return; $wnd.isc.Messaging.messagingURL = URL; }-*/; /** * Get the URL of the messaging servlet. * @return */ public static native String getMessagingURL() /*-{ if ($wnd.isc.Messaging == null) return null; return $wnd.isc.Messaging.messagingURL; }-*/; /** * Specifies how long we wait for the handshake to the server to complete, before trying again. * @param timeout in ms */ public static native void setConnectTimeout(int timeout) /*-{ if ($wnd.isc.Messaging == null) return; $wnd.isc.Messaging.connectTimeout = timeout; }-*/; public static native int getConnectTimeout() /*-{ if ($wnd.isc.Messaging == null) return 0; return $wnd.isc.Messaging.connectTimeout; }-*/; /** * Actually send data to a list of channels. Each browser subscribed to the specified channel will be sent this * data from the server in realtime. * <P> * Note that the data is of type Object - typically this will be just a String. * To send a complex data type such as a Map to the server, use the JSOHelper utility to get a * JavaScript equivalent and pass in the JavaScriptObject. * @param channels * @param data * @param callback */ public static void send (String[] channels, Object data, RPCCallback callback) { checkMessagingLoaded(); sendJS(channels, data, callback); } /** * Actually send data to a channel. Each browser subscribed to the specified channel will be sent this * data from the server in realtime. * <P> * Note that the data is of type Object - typically this will be just a String. * To send a complex data type such as a Map to the server, use the JSOHelper utility to get a * JavaScript equivalent and pass in the JavaScriptObject. * @param channels * @param data * @param callback */ public static void send (String channel, Object data, RPCCallback callback) { String[] channels = new String[] {channel}; send(channels, data, callback); } private static native void sendJS(String[] channels, Object data, RPCCallback callback) /*-{ var jsCallback = function (rpcResponse, data, rpcRequest) { if (callback == null) return; var responseJ = @com.smartgwt.client.rpc.RPCResponse::new(Lcom/google/gwt/core/client/JavaScriptObject;)(rpcResponse); var requestJ = @com.smartgwt.client.rpc.RPCRequest::new(Lcom/google/gwt/core/client/JavaScriptObject;)(rpcRequest); callback.@com.smartgwt.client.rpc.RPCCallback::execute(Lcom/smartgwt/client/rpc/RPCResponse;Ljava/lang/Object;Lcom/smartgwt/client/rpc/RPCRequest;)(responseJ, data, requestJ); }; var jsChannels = @com.smartgwt.client.util.JSOHelper::convertToJavaScriptArray([Ljava/lang/Object;)(channels); $wnd.isc.Messaging.send(jsChannels, data, jsCallback); }-*/; /** * Returns list of channels that we're currently subscribed to. * @return */ public static native String[] getSubscribedChannels () /*-{ if ($wnd.isc.Messaging == null) return null; var channels = $wnd.isc.Messaging.getSubscribedChannels(); // convert to string array and return return @com.smartgwt.client.util.JSOHelper::convertToJavaStringArray(Lcom/google/gwt/core/client/JavaScriptObject;)(channels); }-*/; /** * Call to subscribe to channel. This will cause a reconnect to the server - for this reason we * defer the actuall reconnect to allow for multiple subscribe() calls in sequence. * @param channel name of the channel we are subscribing to. * @param callback this will execute whenever data is received from the server on this messaging channel. */ public static void subscribe(String channel, MessagingCallback callback) { checkMessagingLoaded(); subscribeJS(channel, callback, null); } /** * Call to subscribe to channel. This will cause a reconnect to the server - for this reason we * defer the actuall reconnect to allow for multiple subscribe() calls in sequence. * @param channel name of the channel we are subscribing to. * @param callback this will execute whenever data is received from the server on this messaging channel. * @param selector JMS selector used with Queues to filter the messages that arrive to the channel (optional). */ public static void subscribe(String channel, MessagingCallback callback, String selector) { checkMessagingLoaded(); subscribeJS(channel, callback, selector); } private static native void subscribeJS(String channel, MessagingCallback callback, String selector) /*-{ var jsCallback = function (data) { if (callback == null) return; callback.@com.smartgwt.client.rpc.MessagingCallback::execute(Ljava/lang/Object;)(data); }; $wnd.isc.Messaging.subscribe(channel, jsCallback, null, selector); }-*/; /** * call to unsubscribe from channel(s). This will cause a reconnect to the server - for this reason * we defer the actual reconnect to allow for multiple unsubscribeToChannel() calls in * sequence. * @param channel */ public static native void unsubscribe (String channel) /*-{ if ($wnd.isc.Messaging == null) return; $wnd.isc.Messaging.unsubscribe(channel); }-*/; /** * Returns true if we are currently connected to any channels. * @return */ public static native boolean connected () /*-{ if ($wnd.isc.Messaging == null) return false; var connected = $wnd.isc.Messaging.connected(); if (connected == null) connected = false; return connected; }-*/; /** * disconnect from all channels */ public static native void disconnect() /*-{ if ($wnd.isc.Messaging == null) return; $wnd.isc.Messaging.disconnect(); }-*/; // For the major APIs (subscribe / send) we explicitly check for the Messaging components being present and // throw an error if they are not. private static void checkMessagingLoaded () { if (!messagingLoaded()) { String errorMessage = "Attempt to use Messaging APIs without the optional Realtime Messaging module. " + "Verify that your license includes this optional module and that you have included the necessary " + "client and server-side components in your project."; SC.logWarn(errorMessage); throw new RuntimeException(errorMessage); } } /** * Static method indicating whether the optional RealtimeMessaging module is loaded for the page. * The Messaging class cannot function without this module being present. * @return true if the RealtimeMessaging module is present */ public static boolean messagingLoaded() { return SC.hasRealtimeMessaging(); } }