I'm trying to write a test case which creates a socket and connects to an embedded jetty instance. I'm using
- Jetty: 9.2.0.RC0
- javax.websocket-api & javax.websocket-client-api: 1.0
- javax.websocket server & client impl: 9.1.5.v20140505
Starting the embedded jetty server with the websocket servlet seems to work fine. I took some code from this example. However this line
...
container.connectToServer(SocketClient.class, uri);
...
throws this exception
java.io.IOException: java.util.concurrent.RejectedExecutionException: org.eclipse.jetty.util.thread.NonBlockingThread@6f7476d
at org.eclipse.jetty.websocket.client.WebSocketClient.initialiseClient(WebSocketClient.java:462)
at org.eclipse.jetty.websocket.client.WebSocketClient.connect(WebSocketClient.java:187)
at org.eclipse.jetty.websocket.jsr356.ClientContainer.connect(ClientContainer.java:135)
at org.eclipse.jetty.websocket.jsr356.ClientContainer.connectToServer(ClientContainer.java:172)
at com.playquickly.socket.SocketClient.connect(SocketClient.java:18)
at com.playquickly.servlet.SocketServletTest.testSocket(SocketServletTest.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
Caused by: java.util.concurrent.RejectedExecutionException: org.eclipse.jetty.util.thread.NonBlockingThread@6f7476d
at org.eclipse.jetty.util.thread.QueuedThreadPool.execute(QueuedThreadPool.java:361)
at org.eclipse.jetty.io.SelectorManager.execute(SelectorManager.java:122)
at org.eclipse.jetty.io.SelectorManager.doStart(SelectorManager.java:207)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114)
at org.eclipse.jetty.websocket.client.io.ConnectionManager.doStart(ConnectionManager.java:200)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
at org.eclipse.jetty.websocket.client.WebSocketClient.initialiseClient(WebSocketClient.java:454)
... 30 more
This is my wrapper for stating the embedded jetty server.
public class EmbeddedJetty {
private final Logger LOG = Logger.getLogger(EmbeddedJetty.class.getSimpleName());
private final int port;
private Server server;
public EmbeddedJetty(int port) {
this.port = port;
}
public void start() throws Exception {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
try {
// Initialize javax.websocket layer
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.addEndpoint(SocketServlet.class);
System.out.println("Begin start");
server.start();
System.out.println("End start");
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
public void stop() throws Exception {
server.stop();
LOG.info("Jetty server stopped");
}
}
The client endpoint
@ClientEndpoint(encoders = {MessageCoder.class}, decoders = {MessageCoder.class})
public class SocketClient {
public static Session connect(URI uri) throws Exception {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
// Attempt Connect
return container.connectToServer(SocketClient.class, uri);
} finally {
// Force lifecycle stop when done with container.
// This is to free up threads and resources that the
// JSR-356 container allocates. But unfortunately
// the JSR-356 spec does not handle lifecycles (yet)
if (container instanceof LifeCycle) {
((LifeCycle) container).stop();
}
}
}
@OnMessage
public void onMessage(Message msg, Session session) {
System.out.println(session.getId() + ": " + msg.toString());
}
}
And the test
public class SocketServletTest {
private static EmbeddedJetty server;
@ClassRule
public static final ExternalResource integrationServer = new ExternalResource() {
@Override
protected void before() throws Throwable {
System.out.println("Starting...");
server = new EmbeddedJetty(8080);
server.start();
System.out.println("Started");
}
};
@Before
public void setUp() throws Exception {
}
@After
public void shutdown() throws Exception {
server.stop();
}
@Test
public void testSocket() throws Exception {
URI uri = server.getWebsocketUri(SocketServlet.class);
Session s1 = SocketClient.connect(uri);
}
}
Don't mix versions of Jetty.
This is an unfortunate side effect of the design of the JSR-356 API. (The Client implementation is the root implementation, and the Server implementation is built on top of that)
The Client container is initialized per JVM, and each server container is initialized per webapp.
Your stacktrace is not Jetty 9.2.0.RC0 as you indicated (the line numbers are off)
https://github.com/eclipse/jetty.project/blob/jetty-9.2.0.RC0/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java#L200
They seem to be from Jetty 9.1.5.v20140505
https://github.com/eclipse/jetty.project/blob/jetty-9.1.5.v20140505/jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/io/ConnectionManager.java#L200
Use Jetty 9.2.2.v20140723 everywhere.
Also, using this version means you can get rid of the finally container.stop() hack.