Reputation: 677
I see lots of tutorials about how to set up JSR356 websockets with an embedded web server of some sort.
But I want to add some websockets to an existing WAR deployed to a stand alone jetty installation, jetty jetty-9.2.3.v20140905, and I can find very little information on this. I can't figure out what is preventing it from working. As I understand it, the annotated server endpoints should be automatically handled by jetty.
ServerEndpoint:
@ServerEndpoint(value = "/myendpoint")
public class MyServerEndpoint {
private Logger logger = Logger.getLogger(this.getClass().getName());
@OnOpen
public void onOpen(Session s) {
logger.info("Server Connected ... " + s.getId());
s.getAsyncRemote().sendText("You are connected to the websocket server");
}
@OnMessage
public void onMessage(String message, Session session) {
// Sent the message back to all connected users
logger.info("Server Session " + session + " Received string message " + message);
for(Session s: session.getOpenSessions()) {
if (s.isOpen()) {
s.getAsyncRemote().sendText(message + " server response");
}
}
}
@OnClose
public void onClose(Session session, CloseReason reason) {
logger.info("Server Session " + session + " closed for reason " + reason);
}
}
ClientEndpoint:
@ClientEndpoint
public class MyClientEndpoint {
private Logger logger = Logger.getLogger(this.getClass().getName());
@OnOpen
public void onOpen(Session s) {
logger.info("Client Connected ... " + s.getId());
s.getAsyncRemote().sendText("hello from the client!");
}
@OnMessage
public void onMessage(String message, Session session) {
logger.info("Client Session " + session + " Received string message " + message);
}
@OnClose
public void onClose(Session session, CloseReason reason) {
logger.info("Client Session " + session + " closed for reason " + reason);
}
}
Here is the code (run inside some existing method) to connect the client to the server
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
String uri = "ws://localhost:8080/myWar/myendpoint";
container.connectToServer(MyClientEndpoint.class, URI.create(uri));
Yet spinning up jetty gives an error on the connectToServer line
2014-10-30 12:26:58.658:WARN:oeja.ServletContainerInitializersStarter:main:
org.eclipse.jetty.websocket.api.InvalidWebSocketException: Unable to instantiate websocket: class java.lang.Class
at org.eclipse.jetty.websocket.jsr356.ClientContainer.newClientEndpointInstance(ClientContainer.java:311)
at org.eclipse.jetty.websocket.jsr356.ClientContainer.connectToServer(ClientContainer.java:172)
All I can think is that the URI is incorrect. If jetty is running on 8080 and my .war is named myWar, and my end point is named myendpoint...is that not the correct URI?
Is there some additional step that must be done to 'activate' the server endpoint to listen for connections? I must be missing something obvious.
Upvotes: 2
Views: 4903
Reputation: 4412
Jetty creates instances of annotated client endpoints using reflection (see /jetty/websocket/jsr356/ClientContainer#newClientEndpointInstance()) but Java is unable to instantiate a non-static inner class that way. The actual cause exception is something like java.lang.NoSuchMethodException: <pkg>.OuterClass$InnerClass.<init>()
but it is swallowed.
Solution: annotated endpoint classes should be not nested or nested static (inner) classes.
Upvotes: 0
Reputation: 49545
Strangely, your error message.
org.eclipse.jetty.websocket.api.InvalidWebSocketException:
Unable to instantiate websocket: class java.lang.Class
Means that the websocket implementation was handed a raw java.lang.Class to instantiate. That's not going to work.
It also means no attempt was made to connect, as the WebSocket class itself was so bad that a connect was impossible.
Here's a short (valid and working) example showing its use.
package jetty.jsr356;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.CountDownLatch;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCodes;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
@ClientEndpoint
public class TestClientAnnotatedClass
{
private static CountDownLatch closeLatch = new CountDownLatch(1);
@OnOpen
public void onOpen(Session session)
{
System.out.println("@OnOpen - " + session);
try
{
session.getBasicRemote().sendText("Rock it with Java WebSocket");
}
catch (IOException e)
{
e.printStackTrace();
}
}
@OnMessage
public void onMessage(Session session, String msg)
{
System.out.println("@OnMessage - ["+msg+"]");
try
{
session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE,"Thanks"));
}
catch (IOException e)
{
e.printStackTrace();
}
}
@OnClose
public void onClose(CloseReason close)
{
System.out.println("@OnClose - " + close);
closeLatch.countDown();
}
public static void main(String[] args)
{
try
{
WebSocketContainer ws = ContainerProvider.getWebSocketContainer();
ws.connectToServer(TestClientAnnotatedClass.class,new URI("ws://echo.websocket.org/?encoding=text"));
closeLatch.await();
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}
You'll see output similar to this
2014-10-30 11:34:19.197:INFO::main: Logging initialized @71ms
@OnOpen - WebSocketSession[websocket=JsrAnnotatedEventDriver[websocket=jetty.jsr356.TestClientAnnotatedClass@5cca5f2c],behavior=CLIENT,connection=WebSocketClientConnection@6a2e714b{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[CLIENT,validating],p=Parser@55465b1f[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@7e087bf5[behavior=CLIENT,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@5f025277[batching=true],incoming=JsrAnnotatedEventDriver[websocket=jetty.jsr356.TestClientAnnotatedClass@5cca5f2c],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.jsr356.JsrSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]]
@OnMessage - [Rock it with Java WebSocket]
@OnClose - CloseReason[1000,Thanks]
Upvotes: 2