Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Real-Time Messages sent, and not received.

    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:
    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.
    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:
    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() + "  <<<");
      }
    }
    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):
    Code:
             messaging.keepaliveInterval: 3000
             messaging.keepaliveReestablishDelay: 1000
             messaging.connectTimeout: 4000
             messaging.connectionTTL: 120000
             messaging.flushBufferSize: 8096
             messaging.dispatcherImplementer: com.isomorphic.messaging.LocalMessageDispatcher
    Finally, I un-commented this paragraph in web.xml:
    Code:
          <servlet>
            <servlet-name>MessagingServlet</servlet-name>
            <servlet-class>com.isomorphic.messaging.MessagingServlet</servlet-class>
          </servlet>
    The final clue I have is that the Eclipse Console shows this:
    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
    The really curious thing to me is that the GET URL contains a snippet which when URL decoded reads:
    Code:
    subscribedChannels={
        pushMessage:{
            subscriptionCallback:null
        }
    }
    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?
    Last edited by siegersallee; 29 Oct 2015, 14:19. Reason: Clarified a little and fixed some spelling.

    #2
    The Messaging servlet is not where the client is expecting it, hence the 404 status code.

    Adjust either the path where you registered the servlet in web.xml, or the client-side setting for messagingURL, so that they match.

    Comment


      #3
      Thanks! It turns out I had to change the MessagingServlet servlet-mapping in web.xml, from /sc/messaging/* to /contextName/sc/messaging/*, in case anyone wants to know. At least, that works in Classic Dev Mode.

      Comment

      Working...
      X