Merge pull request #4810 from eclipse/jetty-10.0.x-LinkageErrorInvestigation
Issue #4800 - fix WebSocket LinkageError and invalid PathParam type handling
This commit is contained in:
commit
07551baef7
|
@ -40,11 +40,14 @@ import org.eclipse.jetty.client.HttpClient;
|
|||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
|
||||
import org.eclipse.jetty.websocket.core.exception.UpgradeException;
|
||||
import org.eclipse.jetty.websocket.core.exception.WebSocketTimeoutException;
|
||||
import org.eclipse.jetty.websocket.javax.common.ConfiguredEndpoint;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketContainer;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandler;
|
||||
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
|
||||
|
||||
/**
|
||||
* Container for Client use of the javax.websocket API.
|
||||
|
@ -131,7 +134,7 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
|
|||
{
|
||||
if (error != null)
|
||||
{
|
||||
futureSession.completeExceptionally(error);
|
||||
futureSession.completeExceptionally(convertCause(error));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -147,6 +150,18 @@ public class JavaxWebSocketClientContainer extends JavaxWebSocketContainer imple
|
|||
return futureSession;
|
||||
}
|
||||
|
||||
public static Throwable convertCause(Throwable error)
|
||||
{
|
||||
if (error instanceof UpgradeException ||
|
||||
error instanceof WebSocketTimeoutException)
|
||||
return new IOException(error);
|
||||
|
||||
if (error instanceof InvalidWebSocketException)
|
||||
return new DeploymentException(error.getMessage(), error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
private Session connect(ConfiguredEndpoint configuredEndpoint, URI destURI) throws IOException
|
||||
{
|
||||
Objects.requireNonNull(configuredEndpoint, "WebSocket configured endpoint cannot be null");
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.lang.annotation.Annotation;
|
|||
import java.lang.reflect.Method;
|
||||
import javax.websocket.server.PathParam;
|
||||
|
||||
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.util.InvokerUtils;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +41,7 @@ public class PathParamIdentifier implements InvokerUtils.ParamIdentifier
|
|||
{
|
||||
if (anno.annotationType().equals(PathParam.class))
|
||||
{
|
||||
validateType(paramType);
|
||||
PathParam pathParam = (PathParam)anno;
|
||||
return new InvokerUtils.Arg(paramType, pathParam.value());
|
||||
}
|
||||
|
@ -47,4 +49,22 @@ public class PathParamIdentifier implements InvokerUtils.ParamIdentifier
|
|||
}
|
||||
return new InvokerUtils.Arg(paramType);
|
||||
}
|
||||
|
||||
/**
|
||||
* The JSR356 rules for @PathParam only support
|
||||
* String, Primitive Types (and their Boxed version)
|
||||
*/
|
||||
public static void validateType(Class<?> type)
|
||||
{
|
||||
if (!String.class.isAssignableFrom(type) &&
|
||||
!Integer.TYPE.isAssignableFrom(type) &&
|
||||
!Long.TYPE.isAssignableFrom(type) &&
|
||||
!Short.TYPE.isAssignableFrom(type) &&
|
||||
!Float.TYPE.isAssignableFrom(type) &&
|
||||
!Double.TYPE.isAssignableFrom(type) &&
|
||||
!Boolean.TYPE.isAssignableFrom(type) &&
|
||||
!Character.TYPE.isAssignableFrom(type) &&
|
||||
!Byte.TYPE.isAssignableFrom(type))
|
||||
throw new InvalidSignatureException("Unsupported PathParam Type: " + type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,112 +50,121 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
public class WSServer extends LocalServer implements LocalFuzzer.Provider
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WSServer.class);
|
||||
private final Path contextDir;
|
||||
private final String contextPath;
|
||||
private ContextHandlerCollection contexts;
|
||||
private Path webinf;
|
||||
private Path classesDir;
|
||||
private final Path testDir;
|
||||
private ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
|
||||
public WSServer(File testdir, String contextName)
|
||||
public WSServer(Path testDir)
|
||||
{
|
||||
this(testdir.toPath(), contextName);
|
||||
this.testDir = testDir;
|
||||
}
|
||||
|
||||
public WSServer(Path testdir, String contextName)
|
||||
public WebApp createWebApp(String contextName)
|
||||
{
|
||||
this.contextDir = testdir.resolve(contextName);
|
||||
this.contextPath = "/" + contextName;
|
||||
FS.ensureEmpty(contextDir);
|
||||
}
|
||||
|
||||
public void copyClass(Class<?> clazz) throws Exception
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
String endpointPath = TypeUtil.toClassReference(clazz);
|
||||
URL classUrl = cl.getResource(endpointPath);
|
||||
assertThat("Class URL for: " + clazz, classUrl, notNullValue());
|
||||
Path destFile = classesDir.resolve(endpointPath);
|
||||
FS.ensureDirExists(destFile.getParent());
|
||||
File srcFile = new File(classUrl.toURI());
|
||||
IO.copy(srcFile, destFile.toFile());
|
||||
}
|
||||
|
||||
public void copyEndpoint(Class<?> endpointClass) throws Exception
|
||||
{
|
||||
copyClass(endpointClass);
|
||||
}
|
||||
|
||||
public void copyLib(Class<?> clazz, String jarFileName) throws URISyntaxException, IOException
|
||||
{
|
||||
webinf = contextDir.resolve("WEB-INF");
|
||||
FS.ensureDirExists(webinf);
|
||||
Path libDir = webinf.resolve("lib");
|
||||
FS.ensureDirExists(libDir);
|
||||
Path jarFile = libDir.resolve(jarFileName);
|
||||
|
||||
URL codeSourceURL = clazz.getProtectionDomain().getCodeSource().getLocation();
|
||||
assertThat("Class CodeSource URL is file scheme", codeSourceURL.getProtocol(), is("file"));
|
||||
|
||||
File sourceCodeSourceFile = new File(codeSourceURL.toURI());
|
||||
if (sourceCodeSourceFile.isDirectory())
|
||||
{
|
||||
LOG.info("Creating " + jarFile + " from " + sourceCodeSourceFile);
|
||||
JAR.create(sourceCodeSourceFile, jarFile.toFile());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Copying " + sourceCodeSourceFile + " to " + jarFile);
|
||||
IO.copy(sourceCodeSourceFile, jarFile.toFile());
|
||||
}
|
||||
}
|
||||
|
||||
public void copyWebInf(String testResourceName) throws IOException
|
||||
{
|
||||
webinf = contextDir.resolve("WEB-INF");
|
||||
FS.ensureDirExists(webinf);
|
||||
classesDir = webinf.resolve("classes");
|
||||
FS.ensureDirExists(classesDir);
|
||||
Path webxml = webinf.resolve("web.xml");
|
||||
File testWebXml = MavenTestingUtils.getTestResourceFile(testResourceName);
|
||||
IO.copy(testWebXml, webxml.toFile());
|
||||
}
|
||||
|
||||
public WebAppContext createWebAppContext() throws IOException
|
||||
{
|
||||
WebAppContext context = new WebAppContext();
|
||||
context.setContextPath(this.contextPath);
|
||||
context.setBaseResource(new PathResource(this.contextDir));
|
||||
context.setAttribute("org.eclipse.jetty.websocket.javax", Boolean.TRUE);
|
||||
context.addConfiguration(new JavaxWebSocketConfiguration());
|
||||
return context;
|
||||
}
|
||||
|
||||
public void createWebInf() throws IOException
|
||||
{
|
||||
copyWebInf("empty-web.xml");
|
||||
}
|
||||
|
||||
public void deployWebapp(WebAppContext webapp) throws Exception
|
||||
{
|
||||
contexts.addHandler(webapp);
|
||||
contexts.manage(webapp);
|
||||
webapp.setThrowUnavailableOnStartupException(true);
|
||||
webapp.start();
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("{}", webapp.dump());
|
||||
}
|
||||
}
|
||||
|
||||
public Path getWebAppDir()
|
||||
{
|
||||
return this.contextDir;
|
||||
return new WebApp(contextName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Handler createRootHandler(Server server) throws Exception
|
||||
protected Handler createRootHandler(Server server)
|
||||
{
|
||||
contexts = new ContextHandlerCollection();
|
||||
return contexts;
|
||||
}
|
||||
|
||||
public class WebApp
|
||||
{
|
||||
private final WebAppContext context;
|
||||
private final Path contextDir;
|
||||
private final Path webInf;
|
||||
private final Path classesDir;
|
||||
private final Path libDir;
|
||||
|
||||
private WebApp(String contextName)
|
||||
{
|
||||
// Ensure context directory.
|
||||
contextDir = testDir.resolve(contextName);
|
||||
FS.ensureEmpty(contextDir);
|
||||
|
||||
// Ensure WEB-INF directories.
|
||||
webInf = contextDir.resolve("WEB-INF");
|
||||
FS.ensureDirExists(webInf);
|
||||
classesDir = webInf.resolve("classes");
|
||||
FS.ensureDirExists(classesDir);
|
||||
libDir = webInf.resolve("lib");
|
||||
FS.ensureDirExists(libDir);
|
||||
|
||||
// Configure the WebAppContext.
|
||||
context = new WebAppContext();
|
||||
context.setContextPath("/" + contextName);
|
||||
context.setBaseResource(new PathResource(contextDir));
|
||||
context.setAttribute("org.eclipse.jetty.websocket.javax", Boolean.TRUE);
|
||||
context.addConfiguration(new JavaxWebSocketConfiguration());
|
||||
}
|
||||
|
||||
public WebAppContext getWebAppContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
public String getContextPath()
|
||||
{
|
||||
return context.getContextPath();
|
||||
}
|
||||
|
||||
public Path getContextDir()
|
||||
{
|
||||
return contextDir;
|
||||
}
|
||||
|
||||
public void createWebInf() throws IOException
|
||||
{
|
||||
copyWebInf("empty-web.xml");
|
||||
}
|
||||
|
||||
public void copyWebInf(String testResourceName) throws IOException
|
||||
{
|
||||
File testWebXml = MavenTestingUtils.getTestResourceFile(testResourceName);
|
||||
Path webXml = webInf.resolve("web.xml");
|
||||
IO.copy(testWebXml, webXml.toFile());
|
||||
}
|
||||
|
||||
public void copyClass(Class<?> clazz) throws Exception
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
String endpointPath = TypeUtil.toClassReference(clazz);
|
||||
URL classUrl = cl.getResource(endpointPath);
|
||||
assertThat("Class URL for: " + clazz, classUrl, notNullValue());
|
||||
Path destFile = classesDir.resolve(endpointPath);
|
||||
FS.ensureDirExists(destFile.getParent());
|
||||
File srcFile = new File(classUrl.toURI());
|
||||
IO.copy(srcFile, destFile.toFile());
|
||||
}
|
||||
|
||||
public void copyLib(Class<?> clazz, String jarFileName) throws URISyntaxException, IOException
|
||||
{
|
||||
Path jarFile = libDir.resolve(jarFileName);
|
||||
|
||||
URL codeSourceURL = clazz.getProtectionDomain().getCodeSource().getLocation();
|
||||
assertThat("Class CodeSource URL is file scheme", codeSourceURL.getProtocol(), is("file"));
|
||||
|
||||
File sourceCodeSourceFile = new File(codeSourceURL.toURI());
|
||||
if (sourceCodeSourceFile.isDirectory())
|
||||
{
|
||||
LOG.info("Creating " + jarFile + " from " + sourceCodeSourceFile);
|
||||
JAR.create(sourceCodeSourceFile, jarFile.toFile());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Copying " + sourceCodeSourceFile + " to " + jarFile);
|
||||
IO.copy(sourceCodeSourceFile, jarFile.toFile());
|
||||
}
|
||||
}
|
||||
|
||||
public void deploy()
|
||||
{
|
||||
contexts.addHandler(context);
|
||||
contexts.manage(context);
|
||||
context.setThrowUnavailableOnStartupException(true);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{}", context.dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.List;
|
|||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -50,22 +49,21 @@ public class AltFilterTest
|
|||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir.getPath(), "app");
|
||||
wsb.copyWebInf("alt-filter-web.xml");
|
||||
WSServer wsb = new WSServer(testdir.getPath());
|
||||
WSServer.WebApp app = wsb.createWebApp("app");
|
||||
app.copyWebInf("alt-filter-web.xml");
|
||||
// the endpoint (extends javax.websocket.Endpoint)
|
||||
wsb.copyClass(BasicEchoSocket.class);
|
||||
app.copyClass(BasicEchoSocket.class);
|
||||
app.deploy();
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
|
||||
FilterHolder filterWebXml = webapp.getServletHandler().getFilter("wsuf-test");
|
||||
FilterHolder filterWebXml = app.getWebAppContext().getServletHandler().getFilter("wsuf-test");
|
||||
assertThat("Filter[wsuf-test]", filterWebXml, notNullValue());
|
||||
|
||||
FilterHolder filterSCI = webapp.getServletHandler().getFilter("Jetty_WebSocketUpgradeFilter");
|
||||
FilterHolder filterSCI = app.getWebAppContext().getServletHandler().getFilter("Jetty_WebSocketUpgradeFilter");
|
||||
assertThat("Filter[Jetty_WebSocketUpgradeFilter]", filterSCI, nullValue());
|
||||
|
||||
List<Frame> send = new ArrayList<>();
|
||||
|
|
|
@ -28,7 +28,6 @@ import javax.websocket.WebSocketContainer;
|
|||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.javax.tests.EventSocket;
|
||||
import org.eclipse.jetty.websocket.javax.tests.WSServer;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
@ -61,12 +60,13 @@ public class ContainerProviderServerTest
|
|||
public void startServer() throws Exception
|
||||
{
|
||||
Path testdir = MavenTestingUtils.getTargetTestingPath(ContainerProviderServerTest.class.getName());
|
||||
server = new WSServer(testdir, "app");
|
||||
server.createWebInf();
|
||||
server.copyEndpoint(MySocket.class);
|
||||
server = new WSServer(testdir);
|
||||
WSServer.WebApp app = server.createWebApp("app");
|
||||
app.createWebInf();
|
||||
app.copyClass(MySocket.class);
|
||||
app.deploy();
|
||||
|
||||
server.start();
|
||||
WebAppContext webapp = server.createWebAppContext();
|
||||
server.deployWebapp(webapp);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.javax.tests.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
|
||||
import org.eclipse.jetty.logging.StacklessLogging;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.javax.tests.EventSocket;
|
||||
import org.eclipse.jetty.websocket.javax.tests.WSServer;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnJre;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class DeploymentTest
|
||||
{
|
||||
private WSServer server;
|
||||
|
||||
@BeforeEach
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
Path testdir = MavenTestingUtils.getTargetTestingPath(DeploymentTest.class.getName());
|
||||
server = new WSServer(testdir);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadPathParamSignature() throws Exception
|
||||
{
|
||||
WSServer.WebApp app1 = server.createWebApp("test1");
|
||||
app1.createWebInf();
|
||||
app1.copyClass(BadPathParamEndpoint.class);
|
||||
app1.copyClass(DecodedString.class);
|
||||
app1.copyClass(DeploymentTest.class);
|
||||
app1.deploy();
|
||||
app1.getWebAppContext().setThrowUnavailableOnStartupException(false);
|
||||
|
||||
try (StacklessLogging ignore = new StacklessLogging(ServletContainerInitializersStarter.class, WebAppContext.class))
|
||||
{
|
||||
server.start();
|
||||
}
|
||||
|
||||
WebSocketContainer client = ContainerProvider.getWebSocketContainer();
|
||||
EventSocket clientSocket = new EventSocket();
|
||||
|
||||
Throwable error = assertThrows(Throwable.class, () ->
|
||||
client.connectToServer(clientSocket, server.getWsUri().resolve(app1.getContextPath() + "/badonclose/a")));
|
||||
assertThat(error, Matchers.instanceOf(IOException.class));
|
||||
assertThat(error.getMessage(), Matchers.containsString("503 Service Unavailable"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnJre(JRE.JAVA_14) // TODO: Waiting on JDK14 bug at https://bugs.openjdk.java.net/browse/JDK-8244090.
|
||||
public void testDifferentWebAppsWithSameClassInSignature() throws Exception
|
||||
{
|
||||
WSServer.WebApp app1 = server.createWebApp("test1");
|
||||
app1.createWebInf();
|
||||
app1.copyClass(DecodedEndpoint.class);
|
||||
app1.copyClass(StringDecoder.class);
|
||||
app1.copyClass(DecodedString.class);
|
||||
app1.copyClass(DeploymentTest.class);
|
||||
app1.deploy();
|
||||
|
||||
WSServer.WebApp app2 = server.createWebApp("test2");
|
||||
app2.createWebInf();
|
||||
app2.copyClass(DecodedEndpoint.class);
|
||||
app2.copyClass(StringDecoder.class);
|
||||
app2.copyClass(DecodedString.class);
|
||||
app2.copyClass(DeploymentTest.class);
|
||||
app2.deploy();
|
||||
|
||||
server.start();
|
||||
WebSocketContainer client = ContainerProvider.getWebSocketContainer();
|
||||
EventSocket clientSocket = new EventSocket();
|
||||
|
||||
// Test echo and close to endpoint at /test1.
|
||||
Session session = client.connectToServer(clientSocket, server.getWsUri().resolve("/test1"));
|
||||
session.getAsyncRemote().sendText("hello world");
|
||||
assertThat(clientSocket.textMessages.poll(5, TimeUnit.SECONDS), is("hello world"));
|
||||
session.close();
|
||||
assertTrue(clientSocket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(clientSocket.closeReason.getCloseCode(), is(CloseReason.CloseCodes.NORMAL_CLOSURE));
|
||||
|
||||
// Test echo and close to endpoint at /test2.
|
||||
session = client.connectToServer(clientSocket, server.getWsUri().resolve("/test2"));
|
||||
session.getAsyncRemote().sendText("hello world");
|
||||
assertThat(clientSocket.textMessages.poll(5, TimeUnit.SECONDS), is("hello world"));
|
||||
session.close();
|
||||
assertTrue(clientSocket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(clientSocket.closeReason.getCloseCode(), is(CloseReason.CloseCodes.NORMAL_CLOSURE));
|
||||
}
|
||||
|
||||
@ServerEndpoint("/badonopen/{arg}")
|
||||
public static class BadPathParamEndpoint
|
||||
{
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("arg") DecodedString arg)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@ServerEndpoint(value = "/", decoders = {StringDecoder.class})
|
||||
public static class DecodedEndpoint
|
||||
{
|
||||
@OnMessage
|
||||
public void onMessage(Session session, DecodedString message)
|
||||
{
|
||||
session.getAsyncRemote().sendText(message.getString());
|
||||
}
|
||||
}
|
||||
|
||||
public static class DecodedString
|
||||
{
|
||||
public String string = "";
|
||||
|
||||
public DecodedString(String hold)
|
||||
{
|
||||
string = hold;
|
||||
}
|
||||
|
||||
public String getString()
|
||||
{
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringDecoder implements Decoder.Text<DecodedString>
|
||||
{
|
||||
@Override
|
||||
public DecodedString decode(String s) throws DecodeException
|
||||
{
|
||||
return new DecodedString(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDecode(String s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ import com.acme.websocket.BasicEchoEndpointConfigContextListener;
|
|||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -56,21 +55,20 @@ public class EndpointViaConfigTest
|
|||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir.getPath(), "app");
|
||||
wsb.copyWebInf("basic-echo-endpoint-config-web.xml");
|
||||
WSServer wsb = new WSServer(testdir.getPath());
|
||||
WSServer.WebApp app = wsb.createWebApp("app");
|
||||
app.copyWebInf("basic-echo-endpoint-config-web.xml");
|
||||
// the endpoint (extends javax.websocket.Endpoint)
|
||||
wsb.copyClass(BasicEchoEndpoint.class);
|
||||
app.copyClass(BasicEchoEndpoint.class);
|
||||
// the configuration (adds the endpoint)
|
||||
wsb.copyClass(BasicEchoEndpointConfigContextListener.class);
|
||||
app.copyClass(BasicEchoEndpointConfigContextListener.class);
|
||||
app.deploy();
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
URI uri = wsb.getWsUri();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
|
||||
WebSocketCoreClient client = new WebSocketCoreClient();
|
||||
try
|
||||
{
|
||||
|
|
|
@ -28,7 +28,6 @@ import com.acme.websocket.IdleTimeoutOnOpenEndpoint;
|
|||
import com.acme.websocket.IdleTimeoutOnOpenSocket;
|
||||
import org.eclipse.jetty.logging.StacklessLogging;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -51,19 +50,18 @@ public class IdleTimeoutTest
|
|||
@BeforeAll
|
||||
public static void setupServer() throws Exception
|
||||
{
|
||||
server = new WSServer(MavenTestingUtils.getTargetTestingPath(IdleTimeoutTest.class.getName()), "app");
|
||||
server.copyWebInf("idle-timeout-config-web.xml");
|
||||
server = new WSServer(MavenTestingUtils.getTargetTestingPath(IdleTimeoutTest.class.getName()));
|
||||
WSServer.WebApp app = server.createWebApp("app");
|
||||
app.copyWebInf("idle-timeout-config-web.xml");
|
||||
// the endpoint (extends javax.websocket.Endpoint)
|
||||
server.copyClass(IdleTimeoutOnOpenEndpoint.class);
|
||||
app.copyClass(IdleTimeoutOnOpenEndpoint.class);
|
||||
// the configuration that adds the endpoint
|
||||
server.copyClass(IdleTimeoutContextListener.class);
|
||||
app.copyClass(IdleTimeoutContextListener.class);
|
||||
// the annotated socket
|
||||
server.copyClass(IdleTimeoutOnOpenSocket.class);
|
||||
app.copyClass(IdleTimeoutOnOpenSocket.class);
|
||||
app.deploy();
|
||||
|
||||
server.start();
|
||||
|
||||
WebAppContext webapp = server.createWebAppContext();
|
||||
server.deployWebapp(webapp);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
|
|
@ -29,7 +29,6 @@ import javax.websocket.server.ServerEndpoint;
|
|||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -63,18 +62,17 @@ public class LargeAnnotatedTest
|
|||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir.getPath(), "app");
|
||||
wsb.createWebInf();
|
||||
wsb.copyEndpoint(LargeEchoConfiguredSocket.class);
|
||||
WSServer wsb = new WSServer(testdir.getPath());
|
||||
WSServer.WebApp app = wsb.createWebApp("app");
|
||||
app.createWebInf();
|
||||
app.copyClass(LargeEchoConfiguredSocket.class);
|
||||
app.deploy();
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
URI uri = wsb.getWsUri();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
|
||||
WebSocketCoreClient client = new WebSocketCoreClient();
|
||||
try
|
||||
{
|
||||
|
|
|
@ -28,7 +28,6 @@ import com.acme.websocket.LargeEchoDefaultSocket;
|
|||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -53,18 +52,17 @@ public class LargeContainerTest
|
|||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir.getPath(), "app");
|
||||
wsb.copyWebInf("large-echo-config-web.xml");
|
||||
wsb.copyEndpoint(LargeEchoDefaultSocket.class);
|
||||
WSServer wsb = new WSServer(testdir.getPath());
|
||||
WSServer.WebApp app = wsb.createWebApp("app");
|
||||
app.copyWebInf("large-echo-config-web.xml");
|
||||
app.copyClass(LargeEchoDefaultSocket.class);
|
||||
app.deploy();
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
URI uri = wsb.getWsUri();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
|
||||
WebSocketCoreClient client = new WebSocketCoreClient();
|
||||
try
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@ import javax.websocket.server.ServerEndpoint;
|
|||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -87,18 +86,17 @@ public class OnMessageReturnTest
|
|||
@Test
|
||||
public void testEchoReturn() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir.getPath(), "app");
|
||||
wsb.copyWebInf("empty-web.xml");
|
||||
wsb.copyClass(EchoReturnEndpoint.class);
|
||||
WSServer wsb = new WSServer(testdir.getPath());
|
||||
WSServer.WebApp app = wsb.createWebApp("app");
|
||||
app.copyWebInf("empty-web.xml");
|
||||
app.copyClass(EchoReturnEndpoint.class);
|
||||
app.deploy();
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
URI uri = wsb.getWsUri();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
|
||||
WebSocketCoreClient client = new WebSocketCoreClient();
|
||||
try
|
||||
{
|
||||
|
|
|
@ -30,7 +30,6 @@ import com.acme.websocket.PongMessageEndpoint;
|
|||
import com.acme.websocket.PongSocket;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
|
@ -55,17 +54,16 @@ public class PingPongTest
|
|||
public static void startServer() throws Exception
|
||||
{
|
||||
Path testdir = MavenTestingUtils.getTargetTestingPath(PingPongTest.class.getName());
|
||||
server = new WSServer(testdir, "app");
|
||||
server.copyWebInf("pong-config-web.xml");
|
||||
server = new WSServer(testdir);
|
||||
|
||||
server.copyClass(PongContextListener.class);
|
||||
server.copyClass(PongMessageEndpoint.class);
|
||||
server.copyClass(PongSocket.class);
|
||||
WSServer.WebApp app = server.createWebApp("app");
|
||||
app.copyWebInf("pong-config-web.xml");
|
||||
app.copyClass(PongContextListener.class);
|
||||
app.copyClass(PongMessageEndpoint.class);
|
||||
app.copyClass(PongSocket.class);
|
||||
app.deploy();
|
||||
|
||||
server.start();
|
||||
|
||||
WebAppContext webapp = server.createWebAppContext();
|
||||
server.deployWebapp(webapp);
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
|
|
|
@ -93,12 +93,13 @@ public class WebAppClassLoaderTest
|
|||
public void startServer() throws Exception
|
||||
{
|
||||
Path testdir = MavenTestingUtils.getTargetTestingPath(WebAppClassLoaderTest.class.getName());
|
||||
server = new WSServer(testdir, "app");
|
||||
server.createWebInf();
|
||||
server.copyEndpoint(MySocket.class);
|
||||
server = new WSServer(testdir);
|
||||
WSServer.WebApp app = server.createWebApp("app");
|
||||
app.createWebInf();
|
||||
app.copyClass(MySocket.class);
|
||||
app.deploy();
|
||||
webapp = app.getWebAppContext();
|
||||
server.start();
|
||||
webapp = server.createWebAppContext();
|
||||
server.deployWebapp(webapp);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
|
|
@ -113,6 +113,12 @@
|
|||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-felix-webapp</artifactId>
|
||||
|
@ -120,6 +126,13 @@
|
|||
<scope>test</scope>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-websocket-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
<type>war</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-bad-websocket-webapp</artifactId>
|
||||
|
|
|
@ -20,12 +20,14 @@ package org.eclipse.jetty.tests.distribution;
|
|||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
|
@ -37,10 +39,14 @@ import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
|
|||
import org.eclipse.jetty.io.ClientConnector;
|
||||
import org.eclipse.jetty.unixsocket.client.HttpClientTransportOverUnixSockets;
|
||||
import org.eclipse.jetty.unixsocket.server.UnixSocketConnector;
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnJre;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
@ -49,6 +55,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
|||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
@ -410,6 +417,7 @@ public class DistributionTests extends AbstractDistributionTest
|
|||
"",
|
||||
"--jpms",
|
||||
})
|
||||
@DisabledOnJre(JRE.JAVA_14) // TODO: Waiting on JDK14 bug at https://bugs.openjdk.java.net/browse/JDK-8244090.
|
||||
public void testSimpleWebAppWithWebsocket(String arg) throws Exception
|
||||
{
|
||||
String jettyVersion = System.getProperty("jettyVersion");
|
||||
|
@ -427,9 +435,13 @@ public class DistributionTests extends AbstractDistributionTest
|
|||
assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
|
||||
assertEquals(0, run1.getExitValue());
|
||||
|
||||
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-bad-websocket-webapp:war:" + jettyVersion);
|
||||
distribution.installWarFile(war, "test1");
|
||||
distribution.installWarFile(war, "test2");
|
||||
File webApp = distribution.resolveArtifact("org.eclipse.jetty.tests:test-websocket-webapp:war:" + jettyVersion);
|
||||
File badWebApp = distribution.resolveArtifact("org.eclipse.jetty.tests:test-bad-websocket-webapp:war:" + jettyVersion);
|
||||
|
||||
distribution.installWarFile(webApp, "test1");
|
||||
distribution.installWarFile(badWebApp, "test2");
|
||||
distribution.installWarFile(badWebApp, "test3");
|
||||
distribution.installWarFile(webApp, "test4");
|
||||
|
||||
int port = distribution.freePort();
|
||||
String[] args2 = {
|
||||
|
@ -437,26 +449,64 @@ public class DistributionTests extends AbstractDistributionTest
|
|||
"jetty.http.port=" + port//,
|
||||
//"jetty.server.dumpAfterStart=true"
|
||||
};
|
||||
|
||||
try (DistributionTester.Run run2 = distribution.start(args2))
|
||||
{
|
||||
assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS));
|
||||
// we do not test that anymore because it doesn't work for java14
|
||||
//assertFalse(run2.getLogs().stream().anyMatch(s -> s.contains("LinkageError")));
|
||||
assertFalse(run2.getLogs().stream().anyMatch(s -> s.contains("LinkageError")));
|
||||
|
||||
startHttpClient();
|
||||
ContentResponse response = client.GET("http://localhost:" + port + "/test1/index.jsp");
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
assertThat(response.getContentAsString(), containsString("Hello"));
|
||||
assertThat(response.getContentAsString(), not(containsString("<%")));
|
||||
WebSocketClient wsClient = new WebSocketClient(client);
|
||||
wsClient.start();
|
||||
URI serverUri = URI.create("ws://localhost:" + port);
|
||||
|
||||
client.GET("http://localhost:" + port + "/test2/index.jsp");
|
||||
assertEquals(HttpStatus.OK_200, response.getStatus());
|
||||
assertThat(response.getContentAsString(), containsString("Hello"));
|
||||
assertThat(response.getContentAsString(), not(containsString("<%")));
|
||||
// Verify /test1 is able to establish a WebSocket connection.
|
||||
WsListener webSocketListener = new WsListener();
|
||||
Session session = wsClient.connect(webSocketListener, serverUri.resolve("/test1")).get(5, TimeUnit.SECONDS);
|
||||
session.getRemote().sendString("echo message");
|
||||
assertThat(webSocketListener.textMessages.poll(5, TimeUnit.SECONDS), is("echo message"));
|
||||
session.close();
|
||||
assertTrue(webSocketListener.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(webSocketListener.closeCode, is(StatusCode.NO_CODE));
|
||||
|
||||
// Verify that /test2 and /test3 could not be started.
|
||||
ContentResponse response = client.GET(serverUri.resolve("/test2/badonopen/a"));
|
||||
assertEquals(HttpStatus.SERVICE_UNAVAILABLE_503, response.getStatus());
|
||||
client.GET("http://localhost:" + port + "/test3/badonopen/a");
|
||||
assertEquals(HttpStatus.SERVICE_UNAVAILABLE_503, response.getStatus());
|
||||
|
||||
// Verify /test4 is able to establish a WebSocket connection.
|
||||
webSocketListener = new WsListener();
|
||||
session = wsClient.connect(webSocketListener, serverUri.resolve("/test4")).get(5, TimeUnit.SECONDS);
|
||||
session.getRemote().sendString("echo message");
|
||||
assertThat(webSocketListener.textMessages.poll(5, TimeUnit.SECONDS), is("echo message"));
|
||||
session.close();
|
||||
assertTrue(webSocketListener.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(webSocketListener.closeCode, is(StatusCode.NO_CODE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class WsListener implements WebSocketListener
|
||||
{
|
||||
BlockingArrayQueue<String> textMessages = new BlockingArrayQueue<>();
|
||||
private CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
private int closeCode;
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
this.closeCode = statusCode;
|
||||
closeLatch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message)
|
||||
{
|
||||
textMessages.add(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartStopLog4j2Modules() throws Exception
|
||||
{
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.tests.webapp.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
|
@ -28,16 +26,15 @@ import javax.websocket.server.ServerEndpoint;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ServerEndpoint("/onopen/{arg}")
|
||||
public class OnOpenServerEndpoint
|
||||
@ServerEndpoint(value = "/", decoders = {StringSequenceDecoder.class})
|
||||
public class EchoEndpoint
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OnOpenServerEndpoint.class);
|
||||
private static String open = "";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EchoEndpoint.class);
|
||||
|
||||
@OnMessage
|
||||
public String echo(String echo)
|
||||
public String echo(StringSequence echo)
|
||||
{
|
||||
return open + echo;
|
||||
return echo.toString();
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
|
@ -45,12 +42,4 @@ public class OnOpenServerEndpoint
|
|||
{
|
||||
LOGGER.info("Session opened");
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable t)
|
||||
throws IOException
|
||||
{
|
||||
String message = "Error happened:" + t.getMessage();
|
||||
session.getBasicRemote().sendText(message);
|
||||
}
|
||||
}
|
|
@ -18,39 +18,37 @@
|
|||
|
||||
package org.eclipse.jetty.tests.webapp.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ServerEndpoint("/onclose/{arg}")
|
||||
public class OnCloseServerEndpoint
|
||||
public class StringSequence
|
||||
implements CharSequence
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(OnCloseServerEndpoint.class);
|
||||
private static String close = "";
|
||||
public String stringBuffer;
|
||||
|
||||
@OnMessage
|
||||
public String echo(String echo)
|
||||
public StringSequence(String hold)
|
||||
{
|
||||
return close + echo;
|
||||
stringBuffer = hold;
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session)
|
||||
@Override
|
||||
public int length()
|
||||
{
|
||||
LOGGER.info("Session close");
|
||||
return stringBuffer.length();
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable t)
|
||||
throws IOException
|
||||
@Override
|
||||
public char charAt(int index)
|
||||
{
|
||||
String message = "Error happened:" + t.getMessage();
|
||||
session.getBasicRemote().sendText(message);
|
||||
return stringBuffer.charAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end)
|
||||
{
|
||||
return stringBuffer.subSequence(start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return stringBuffer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.tests.webapp.websocket;
|
||||
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
public class StringSequenceDecoder implements Decoder.Text<StringSequence>
|
||||
{
|
||||
@Override
|
||||
public StringSequence decode(String s) throws DecodeException
|
||||
{
|
||||
return new StringSequence(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDecode(String s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue