0

I am trying to build a simple didactic websocket application using spring 4.0, jsf and glassfish 4.0.
I have created a maven web project (because this app has another web component(jsf)), and from this app i`m trying to setup some websockets.

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {      
     registry.addHandler(echoHandler(), "/echo");
}
@Bean
  public WebSocketHandler echoHandler() {
  return new EchoHandler();
  }  
}

and

public class EchoHandler extends TextWebSocketHandler {

  @Override
  public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
      session.sendMessage(message);
  }
}

and on the client side a very simple connect:

<script>
    /* <![CDATA[ */

    var endPointURL = "ws://localhost:8080/liveasterisk/echo";

    var chatClient = null;

    function connect () {
        chatClient = new WebSocket(endPointURL);
        chatClient.onmessage = function (event) {
           alert(event);
        };
    }

    function disconnect () {
        chatClient.close();
    }

    function sendMessage() {    
            chatClient.send("xxx");    
    }

        connect();

    /* ]]> */    
    </script>

The problem is that when the connect() method fires i get a 404 response.

I guess that i have to somehow train jsf to respond to handshake request. All my *.xhtml are mapped to jsf servlet.

So what I`m I missing here ?

I have solved the problem like this:

@ServerEndpoint(value = "/keepalive", configurator = SpringConfigurator.class)
public class KeepAliveEndpoint {

private static Logger logger = Logger.getLogger(KeepAliveEndpoint.class);

@Autowired
private KeepAliveService keepAliveService;

  private List<Session> sessions = new ArrayList<Session>();

  @OnOpen
  public void onOpen(Session session) {    
      sessions.add(session);
      System.out.println("onOpen: " + session.getId()+" list size: " + sessions.size());
  }

  @OnClose
  public void onClose(Session session) {
    System.out.println("onClose: " + session.getId());
    sessions.remove(session);
  }

  @OnMessage
  public void handleMessage(Session session, String message) {    

      try{            
          Long userId = Long.parseLong(message);
          keepAliveService.keepAlive(userId);

      }catch(NumberFormatException nfe){
          try {
            session.getBasicRemote().sendText("Cannot perform live update for your status");
        } catch (IOException e) {               
            e.printStackTrace();
        }

      }

  }

}

so now I have a sockets exposed via jsf and I can inject "services" with @Autowired in this endpoint.
And with this js code:

  <script type="text/javascript">
      var host = "ws://localhost:8080/myApp/keepalive";
      var wSocket = new WebSocket(host);
      var browserSupport = ("WebSocket" in window) ? true : false;

      // called  body onLoad()
      function initializeReception() {

        if (browserSupport) {

          wSocket.onopen = function(){                        
            setInterval(function(){wSocket.send('<h:outputText value="#{managedBean.userDTO.id}" />')}, 300000);              
          };

            // called when a message is received
          wSocket.onmessage = function(event) {        
            alert(event.data);
          };

          // on error handler
          wSocket.onError = function(event) {        
                alert('An error has occured '+event.data+'.');
          };

          // called when socket closes
          wSocket.onclose = function(){
          // websocket is closed.
          //alert("Connection is closed...");
          };
        }
        else {              
          // The browser doesn't support WebSocket
          alert("WebSocket is NOT supported by your Browser!");
        }
      }  

      initializeReception();            
</script>
Videanu Adrian
  • 972
  • 3
  • 16
  • 41

1 Answers1

0

The above configuration is for use with Spring MVC's DispatcherServlet. Do you have one configured in the web application? Depending on the servlet mapping (not shown above) you'll most likely need one more part added to the URL to match the servlet mapping.

The longer explanation is that @EnableWebSocket creates a HandlerMapping that maps "/echo" to the WebSocketHandler. That HandlerMapping needs to reside in the configuration of the DispatcherServlet in order for the HTTP handshake to be processed.

Rossen Stoyanchev
  • 4,910
  • 23
  • 26