title: why my tomcat websocket OnMessage annotated method never get called?
body: <p>I am trying to use websocket with tomcat 8.5 to monitor a log file, but my code doesn't work as expected:</p>
  
  <pre><code>import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.RandomAccessFile;
  import java.io.Writer;
  
  import javax.websocket.CloseReason;
  import javax.websocket.Endpoint;
  import javax.websocket.EndpointConfig;
  import javax.websocket.OnMessage;
  import javax.websocket.Session;
  import javax.websocket.server.ServerEndpoint;
  
  @ServerEndpoint(value = "/ws/log")
  public class LogEndPoint extends Endpoint {
  
      private Thread tailer = null;
  
      @Override
      public void onOpen(Session session, EndpointConfig config) {
          System.out.println("---------------- Connection Established ----------------");
          System.out.println("----message handlers's size in current size=" + session.getMessageHandlers().size());
  //      session.addMessageHandler(new MessageHandler.Whole&lt;String&gt;() {
  //
  //          @Override
  //          public void onMessage(String message) {
  //              System.out.println("&lt;&lt;&lt;&lt; " + message);
  //              try {
  //                  tailer = new Thread(new FileTailer(getFilePath(message), session.getBasicRemote().getSendWriter(), 200));
  //              } catch (IOException e) {
  //                  e.printStackTrace();
  //                  try {
  //                      session.close();
  //                  } catch (IOException e1) {
  //                      e1.printStackTrace();
  //                  }
  //              }
  //          }
  
  //      });
      }
  
      @OnMessage
      public void doOnMessage(String message, Session session) {
          System.out.println("&lt;&lt;&lt;&lt; " + message);
          try {
              tailer = new Thread(new FileTailer(getFilePath(message), session.getBasicRemote().getSendWriter(), 200));
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
  
      @Override
      public void onClose(Session session, CloseReason closeReason) {
          System.out.println("---------------- Connection Closed ----------------");
          if(tailer != null)
              tailer.interrupt();
      }
  
      private String getFilePath(String name){
          switch (name) {
          case "app": {
              return "d:\\myApp.log";
          }
          case "server": {
              return "d:\\myServer.log";
          }
          }
          throw new RuntimeException("invalid log type");
      }
  
      @Override
      public void onError(Session session, Throwable throwable) {
          System.out.println("---------------- Error Occured ----------------");
          throwable.printStackTrace();
          if(tailer != null)
              tailer.interrupt();
      }
  
      class FileTailer implements Runnable{
  
          private int interval = 200;
  
          private long lastKnownPosition;
  
          private RandomAccessFile file;
  
          private Writer writer;
  
          FileTailer(String file, Writer writer, int interval){
              this.interval = interval;
              this.writer = writer;
              try(RandomAccessFile tmp = new RandomAccessFile(file, "r")){
                  this.file = tmp;
                  lastKnownPosition = file.length();
              } catch (FileNotFoundException e) {
                  e.printStackTrace();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
  
          @Override
          public void run() {
              followFile();
          }
  
          private void followFile(){
              while(!Thread.currentThread().isInterrupted()){
                  try {
                      Thread.sleep(interval);
                      if(file.length() &gt; lastKnownPosition){
                          file.seek(lastKnownPosition);
                          String line = null;
                          while((line = file.readLine()) != null){
                              writer.write(line);
                          }
                          lastKnownPosition = file.getFilePointer();
                      }else{
                          System.out.println("after " +  interval + " ms, no new data has been written into the file");
                      }
                  } catch (InterruptedException | IOException e) {
                      e.printStackTrace();
                  }finally{
                      try {
                          if(file != null)
                              file.close();
                      } catch (IOException e1) {
                          e1.printStackTrace();
                      }
                  }
              }
          }
      }
  
  
  
  }
  </code></pre>
  
  <p>I use javascript to send some text message to this end point, but the <code>doOnMessage</code> method never get called.</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;title&gt;WebSocket Logging Demo&lt;/title&gt;
  &lt;style&gt;
      #shell{
          background-color : #000;
          color : #fff;
      }
  &lt;/style&gt;
  &lt;script&gt;
  var socket = null;
  
  function start(){
      console.log('start');
      socket = new WebSocket('ws://localhost:9080/labws/ws/log');
  
      socket.onopen = function(event) {
          console.log('onopen');
          var label = document.getElementById('shell');
          label.value = label.value + '-------------Connection Established-------------\n';
          socket.send('app');
          label.value = label.value + '&gt;&gt;&gt;&gt; app\n';
      };
  
      socket.onmessage = function(event) {
          console.log('onmessage: ' + event.data);
          var label = document.getElementById('shell');
          label.value = label.value + '&lt;&lt;&lt;&lt; ' + event.data + '\n';
      };
  
  
  }
  
  function stop(){
      console.log('stop');
      var label = document.getElementById('shell');
      label.value =  label.value + '-------------Connection Closed-------------\n';
  //  if (socket.readyState === WebSocket.OPEN) {
          socket.close(1000, 'byebye');
  //  }
  }
  &lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;div&gt;
       &lt;h3&gt;WebSocket Logging Demo&lt;/h3&gt;
       &lt;input type="button" value="start"  onclick="start()"/&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;input type="button" value="stop"  onclick="stop()" /&gt;&lt;br /&gt;
       &lt;textarea id="shell" rows="10" cols="300"&gt;&lt;/textarea&gt;
  &lt;/div&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>The interest thing is the commented part in <code>onOpen</code> method, if I add a message handler manually, it works as I expected. I just begin to learn websocket, did I miss any thing?</p>
  
  <h2><strong>Edit</strong></h2>
  
  <p>for other people face the same problem, the accepted anwser had make a good point, but I want to add my two cents:</p>
  
  <p>The JSR 356 Chapter 2 said this:</p>
  
  <pre><code>There are two main means by which an endpoint can be created. The first means is to implement certain of
  the API classes from the Java WebSocket API with the required behavior to handle the endpoint lifecycle,
  consume and send messages, publish itself, or connect to a peer. Often, this specification will refer to this
  kind of endpoint as a programmatic endpoint. The second means is to decorate a Plain Old Java Object
  (POJO) with certain of the annotations from the Java WebSocket API. The implementation then takes these
  annotated classes and creates the appropriate objects at runtime to deploy the POJO as a websocket endpoint.
  Often, this specification will refer to this kind of endpoint as an annotated endpoint. The specification will
  refer to an endpoint when it is talking about either kind of endpoint: programmatic or annotated.
  </code></pre>
  
  <p>basicly, that's the annotation driven mode and interface mode mentioned by the accepted answer, but the sepecification doesn't say that we can't use a mixed mode!
  so It depends on implementations, for example, my above code works on jetty.</p>