Issue #4548 - clean up websocket removing duplicated and unused classes (#4549)

Create new module websocket-util which contains implementation classes shared by websocket-jetty and websocket-javax. Many of these classes had to be changed as the javax and jetty versions of them differed slightly.

Also includes general cleanups, removed unused interfaces and classes, etc..
This commit is contained in:
Lachlan 2020-02-18 21:43:54 +11:00 committed by GitHub
parent 59ae7767a4
commit 5fe202f29f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
146 changed files with 657 additions and 4386 deletions

View File

@ -147,16 +147,17 @@ public class TestOSGiUtil
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-plus").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-annotations").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-core").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-api").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-common").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-servlet").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-util").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-api").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-server").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-client").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-javax-common").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-javax-client").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-javax-server").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-jetty-common").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.toolchain").artifactId("jetty-javax-websocket-api").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-javax-server").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-javax-client").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.websocket").artifactId("websocket-javax-common").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-boot").versionAsInProject().start());
return res;
}

View File

@ -16,6 +16,7 @@
<modules>
<module>websocket-core</module>
<module>websocket-servlet</module>
<module>websocket-util</module>
<!-- Jetty WebSocket Implementation -->
<module>websocket-jetty-api</module>
<module>websocket-jetty-common</module>

View File

@ -81,6 +81,12 @@ public interface CoreSession extends OutgoingFrames, Configuration
*/
Behavior getBehavior();
/**
* TODO
* @return
*/
WebSocketComponents getWebSocketComponents();
/**
* @return The shared ByteBufferPool
*/
@ -214,6 +220,12 @@ public interface CoreSession extends OutgoingFrames, Configuration
return null;
}
@Override
public WebSocketComponents getWebSocketComponents()
{
return null;
}
@Override
public ByteBufferPool getByteBufferPool()
{

View File

@ -425,7 +425,7 @@ public abstract class ClientUpgradeRequest extends HttpRequest implements Respon
extensionStack,
WebSocketConstants.SPEC_VERSION_STRING);
WebSocketCoreSession coreSession = new WebSocketCoreSession(frameHandler, Behavior.CLIENT, negotiated);
WebSocketCoreSession coreSession = new WebSocketCoreSession(frameHandler, Behavior.CLIENT, negotiated, wsClient.getWebSocketComponents());
customizer.customize(coreSession);
HttpClient httpClient = wsClient.getHttpClient();

View File

@ -45,6 +45,7 @@ import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.core.IncomingFrames;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.OutgoingFrames;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.WebSocketConstants;
import org.eclipse.jetty.websocket.core.exception.CloseException;
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
@ -63,6 +64,7 @@ public class WebSocketCoreSession implements IncomingFrames, CoreSession, Dumpab
private static final Logger LOG = Log.getLogger(WebSocketCoreSession.class);
private static final CloseStatus NO_CODE = new CloseStatus(CloseStatus.NO_CODE);
private final WebSocketComponents components;
private final Behavior behavior;
private final WebSocketSessionState sessionState = new WebSocketSessionState();
private final FrameHandler handler;
@ -81,8 +83,9 @@ public class WebSocketCoreSession implements IncomingFrames, CoreSession, Dumpab
private Duration writeTimeout = WebSocketConstants.DEFAULT_WRITE_TIMEOUT;
private final ContextHandler contextHandler;
public WebSocketCoreSession(FrameHandler handler, Behavior behavior, Negotiated negotiated)
public WebSocketCoreSession(FrameHandler handler, Behavior behavior, Negotiated negotiated, WebSocketComponents components)
{
this.components = components;
this.handler = handler;
this.behavior = behavior;
this.negotiated = negotiated;
@ -794,6 +797,12 @@ public class WebSocketCoreSession implements IncomingFrames, CoreSession, Dumpab
return behavior;
}
@Override
public WebSocketComponents getWebSocketComponents()
{
return components;
}
@Override
public String toString()
{

View File

@ -137,7 +137,7 @@ public abstract class AbstractHandshaker implements Handshaker
Negotiated negotiated = new Negotiated(baseRequest.getHttpURI().toURI(), protocol, baseRequest.isSecure(), extensionStack, WebSocketConstants.SPEC_VERSION_STRING);
// Create the Session
WebSocketCoreSession coreSession = newWebSocketCoreSession(handler, negotiated);
WebSocketCoreSession coreSession = newWebSocketCoreSession(handler, negotiated, components);
if (defaultCustomizer != null)
defaultCustomizer.customize(coreSession);
negotiator.customize(coreSession);
@ -200,9 +200,9 @@ public abstract class AbstractHandshaker implements Handshaker
return true;
}
protected WebSocketCoreSession newWebSocketCoreSession(FrameHandler handler, Negotiated negotiated)
protected WebSocketCoreSession newWebSocketCoreSession(FrameHandler handler, Negotiated negotiated, WebSocketComponents components)
{
return new WebSocketCoreSession(handler, Behavior.SERVER, negotiated);
return new WebSocketCoreSession(handler, Behavior.SERVER, negotiated, components);
}
protected abstract WebSocketConnection createWebSocketConnection(Request baseRequest, WebSocketCoreSession coreSession);

View File

@ -64,7 +64,7 @@ public class GeneratorFrameFlagsTest
{
ExtensionStack exStack = new ExtensionStack(components, Behavior.SERVER);
exStack.negotiate(new LinkedList<>(), new LinkedList<>());
this.coreSession = new WebSocketCoreSession(new TestMessageHandler(), Behavior.CLIENT, Negotiated.from(exStack));
this.coreSession = new WebSocketCoreSession(new TestMessageHandler(), Behavior.CLIENT, Negotiated.from(exStack), components);
}
@ParameterizedTest

View File

@ -49,13 +49,14 @@ public class GeneratorTest
private static Generator generator = new Generator();
private static WebSocketCoreSession coreSession = newWebSocketCoreSession(Behavior.SERVER);
private static WebSocketComponents components = new WebSocketComponents();
private static WebSocketCoreSession newWebSocketCoreSession(Behavior behavior)
{
WebSocketComponents components = new WebSocketComponents();
ExtensionStack exStack = new ExtensionStack(components, Behavior.SERVER);
exStack.negotiate(new LinkedList<>(), new LinkedList<>());
return new WebSocketCoreSession(new TestMessageHandler(), behavior, Negotiated.from(exStack));
return new WebSocketCoreSession(new TestMessageHandler(), behavior, Negotiated.from(exStack), components);
}
/**

View File

@ -56,7 +56,7 @@ public class ParserCapture
WebSocketComponents components = new WebSocketComponents();
ExtensionStack exStack = new ExtensionStack(components, Behavior.SERVER);
exStack.negotiate(new LinkedList<>(), new LinkedList<>());
this.coreSession = new WebSocketCoreSession(new TestMessageHandler(), behavior, Negotiated.from(exStack));
this.coreSession = new WebSocketCoreSession(new TestMessageHandler(), behavior, Negotiated.from(exStack), components);
coreSession.setAutoFragment(false);
coreSession.setMaxFrameSize(0);
this.parser = new Parser(components.getBufferPool(), coreSession);

View File

@ -166,7 +166,7 @@ public class ExtensionTool
{
ExtensionStack exStack = new ExtensionStack(components, Behavior.SERVER);
exStack.negotiate(new LinkedList<>(), new LinkedList<>());
WebSocketCoreSession coreSession = new WebSocketCoreSession(new TestMessageHandler(), Behavior.SERVER, Negotiated.from(exStack));
WebSocketCoreSession coreSession = new WebSocketCoreSession(new TestMessageHandler(), Behavior.SERVER, Negotiated.from(exStack), components);
return coreSession;
}
}

View File

@ -605,7 +605,7 @@ public class PerMessageDeflateExtensionTest extends AbstractExtensionTest
ExtensionStack exStack = new ExtensionStack(components, Behavior.SERVER);
exStack.negotiate(new LinkedList<>(), new LinkedList<>());
WebSocketCoreSession coreSession = new WebSocketCoreSession(new TestMessageHandler(), Behavior.SERVER, Negotiated.from(exStack));
WebSocketCoreSession coreSession = new WebSocketCoreSession(new TestMessageHandler(), Behavior.SERVER, Negotiated.from(exStack), components);
configuration.customize(configuration);
return coreSession;
}

View File

@ -15,6 +15,11 @@
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-javax-common</artifactId>

View File

@ -25,8 +25,9 @@ module org.eclipse.jetty.websocket.javax.client
exports org.eclipse.jetty.websocket.javax.client;
requires transitive org.eclipse.jetty.client;
requires org.eclipse.jetty.websocket.core;
requires transitive org.eclipse.jetty.websocket.javax.common;
requires org.eclipse.jetty.websocket.core;
requires org.eclipse.jetty.websocket.util;
provides ContainerProvider with JavaxWebSocketClientContainerProvider;
}

View File

@ -24,7 +24,7 @@ import javax.websocket.ClientEndpoint;
import javax.websocket.ClientEndpointConfig;
import org.eclipse.jetty.websocket.javax.common.ClientEndpointConfigWrapper;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
public class AnnotatedClientEndpointConfig extends ClientEndpointConfigWrapper
{

View File

@ -1,52 +0,0 @@
//
// ========================================================================
// 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.client;
import java.net.URI;
import java.security.Principal;
import org.eclipse.jetty.websocket.core.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.javax.common.UpgradeRequest;
/**
* Representing the Jetty {@link org.eclipse.jetty.client.HttpClient}'s {@link org.eclipse.jetty.client.HttpRequest}
* in the {@link UpgradeRequest} interface.
*/
public class DelegatedJavaxClientUpgradeRequest implements UpgradeRequest
{
private final ClientUpgradeRequest delegate;
public DelegatedJavaxClientUpgradeRequest(ClientUpgradeRequest delegate)
{
this.delegate = delegate;
}
@Override
public Principal getUserPrincipal()
{
// User Principal not available from Client API
return null;
}
@Override
public URI getRequestURI()
{
return delegate.getURI();
}
}

View File

@ -1,58 +0,0 @@
//
// ========================================================================
// 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.client;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jetty.client.HttpResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.javax.common.UpgradeResponse;
/**
* Representing the Jetty {@link org.eclipse.jetty.client.HttpClient}'s {@link HttpResponse}
* in the {@link UpgradeResponse} interface.
*/
public class DelegatedJavaxClientUpgradeResponse implements UpgradeResponse
{
private HttpResponse delegate;
public DelegatedJavaxClientUpgradeResponse(HttpResponse response)
{
this.delegate = response;
}
@Override
public String getAcceptedSubProtocol()
{
return this.delegate.getHeaders().get(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL);
}
@Override
public List<ExtensionConfig> getExtensions()
{
List<String> rawExtensions = delegate.getHeaders().getValuesList(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
if (rawExtensions == null || rawExtensions.isEmpty())
return Collections.emptyList();
return rawExtensions.stream().map((parameterizedName) -> ExtensionConfig.parse(parameterizedName)).collect(Collectors.toList());
}
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.websocket.javax.client;
import java.net.URI;
import java.security.Principal;
import org.eclipse.jetty.client.HttpResponse;
import org.eclipse.jetty.io.EndPoint;
@ -28,25 +29,20 @@ import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandler;
import org.eclipse.jetty.websocket.javax.common.UpgradeRequest;
public class JavaxClientUpgradeRequest extends ClientUpgradeRequest
public class JavaxClientUpgradeRequest extends ClientUpgradeRequest implements UpgradeRequest
{
private final JavaxWebSocketClientContainer containerContext;
private final JavaxWebSocketFrameHandler frameHandler;
public JavaxClientUpgradeRequest(JavaxWebSocketClientContainer clientContainer, WebSocketCoreClient coreClient, URI requestURI, Object websocketPojo)
{
super(coreClient, requestURI);
this.containerContext = clientContainer;
UpgradeRequest upgradeRequest = new DelegatedJavaxClientUpgradeRequest(this);
frameHandler = containerContext.newFrameHandler(websocketPojo, upgradeRequest);
frameHandler = clientContainer.newFrameHandler(websocketPojo, this);
}
@Override
public void upgrade(HttpResponse response, EndPoint endPoint)
{
frameHandler.setUpgradeRequest(new DelegatedJavaxClientUpgradeRequest(this));
frameHandler.setUpgradeResponse(new DelegatedJavaxClientUpgradeResponse(response));
frameHandler.setUpgradeRequest(this);
super.upgrade(response, endPoint);
}
@ -55,4 +51,17 @@ public class JavaxClientUpgradeRequest extends ClientUpgradeRequest
{
return frameHandler;
}
@Override
public Principal getUserPrincipal()
{
// User Principal not available from Client API
return null;
}
@Override
public URI getRequestURI()
{
return getURI();
}
}

View File

@ -25,7 +25,7 @@ import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketContainer;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.InvokerUtils;
public class JavaxWebSocketClientFrameHandlerFactory extends JavaxWebSocketFrameHandlerFactory
{

View File

@ -71,6 +71,11 @@
<artifactId>websocket-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-javax-websocket-api</artifactId>

View File

@ -22,10 +22,10 @@ module org.eclipse.jetty.websocket.javax.common
exports org.eclipse.jetty.websocket.javax.common.decoders;
exports org.eclipse.jetty.websocket.javax.common.encoders;
exports org.eclipse.jetty.websocket.javax.common.messages;
exports org.eclipse.jetty.websocket.javax.common.util;
requires transitive jetty.websocket.api;
requires transitive org.eclipse.jetty.http;
requires transitive org.eclipse.jetty.io;
requires transitive org.eclipse.jetty.websocket.core;
requires transitive org.eclipse.jetty.websocket.util;
}

View File

@ -1,48 +0,0 @@
//
// ========================================================================
// 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.common;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class CompletableFutureCallback extends CompletableFuture<Callback> implements Callback
{
private static final Logger LOG = Log.getLogger(CompletableFutureCallback.class);
@Override
public void failed(Throwable cause)
{
if (LOG.isDebugEnabled())
LOG.debug("failed()", cause);
completeExceptionally(cause);
}
@Override
public void succeeded()
{
if (LOG.isDebugEnabled())
LOG.debug("succeeded()");
complete(this);
}
}

View File

@ -1,38 +0,0 @@
//
// ========================================================================
// 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.common;
/**
* Thrown when a duplicate coder is encountered when attempting to identify a Endpoint's metadata ({@link javax.websocket.Decoder} or {@link javax.websocket.Encoder})
* TODO: is this still needed?
*/
public class DuplicateCoderException extends InvalidWebSocketException
{
private static final long serialVersionUID = -3049181444035417170L;
public DuplicateCoderException(String message)
{
super(message);
}
public DuplicateCoderException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -33,9 +33,9 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.messages.MessageOutputStream;
import org.eclipse.jetty.websocket.javax.common.messages.MessageWriter;
import org.eclipse.jetty.websocket.javax.common.util.TextUtil;
import org.eclipse.jetty.websocket.util.TextUtil;
import org.eclipse.jetty.websocket.util.messages.MessageOutputStream;
import org.eclipse.jetty.websocket.util.messages.MessageWriter;
public class JavaxWebSocketAsyncRemote extends JavaxWebSocketRemoteEndpoint implements javax.websocket.RemoteEndpoint.Async
{

View File

@ -33,7 +33,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.util.TextUtil;
import org.eclipse.jetty.websocket.util.TextUtil;
import static java.nio.charset.StandardCharsets.UTF_8;

View File

@ -52,10 +52,11 @@ import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryMessageSin
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryStreamMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.PartialByteArrayMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.PartialByteBufferMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.PartialStringMessageSink;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialByteArrayMessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialByteBufferMessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialStringMessageSink;
public class JavaxWebSocketFrameHandler implements FrameHandler
{
@ -99,7 +100,6 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
private MethodHandle pongHandle;
private UpgradeRequest upgradeRequest;
private UpgradeResponse upgradeResponse;
private EndpointConfig endpointConfig;
private final Map<Byte, RegisteredMessageHandler> messageHandlerMap = new HashMap<>();
@ -383,7 +383,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
if (byte[].class.isAssignableFrom(clazz))
{
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
MessageSink messageSink = new PartialByteArrayMessageSink(session, partialMessageHandler);
MessageSink messageSink = new PartialByteArrayMessageSink(coreSession, partialMessageHandler);
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
metadata.handle = partialMessageHandler;
@ -393,7 +393,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
else if (ByteBuffer.class.isAssignableFrom(clazz))
{
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
MessageSink messageSink = new PartialByteBufferMessageSink(session, partialMessageHandler);
MessageSink messageSink = new PartialByteBufferMessageSink(coreSession, partialMessageHandler);
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
metadata.handle = partialMessageHandler;
@ -403,7 +403,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
else if (String.class.isAssignableFrom(clazz))
{
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
MessageSink messageSink = new PartialStringMessageSink(session, partialMessageHandler);
MessageSink messageSink = new PartialStringMessageSink(coreSession, partialMessageHandler);
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
JavaxWebSocketFrameHandlerMetadata.MessageMetadata metadata = new JavaxWebSocketFrameHandlerMetadata.MessageMetadata();
metadata.handle = partialMessageHandler;
@ -460,7 +460,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
{
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
Decoder.Binary<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
MessageSink messageSink = new DecodedBinaryMessageSink(session, decoder, wholeMsgMethodHandle);
MessageSink messageSink = new DecodedBinaryMessageSink(coreSession, decoder, wholeMsgMethodHandle);
metadata.sinkClass = messageSink.getClass();
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
this.binaryMetadata = metadata;
@ -469,7 +469,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
{
assertBasicTypeNotRegistered(OpCode.BINARY, this.binaryMetadata, handler.getClass().getName());
Decoder.BinaryStream<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
MessageSink messageSink = new DecodedBinaryStreamMessageSink(session, decoder, wholeMsgMethodHandle);
MessageSink messageSink = new DecodedBinaryStreamMessageSink(coreSession, decoder, wholeMsgMethodHandle);
metadata.sinkClass = messageSink.getClass();
this.binarySink = registerMessageHandler(OpCode.BINARY, clazz, handler, messageSink);
this.binaryMetadata = metadata;
@ -478,7 +478,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
{
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
Decoder.Text<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
MessageSink messageSink = new DecodedTextMessageSink(session, decoder, wholeMsgMethodHandle);
MessageSink messageSink = new DecodedTextMessageSink(coreSession, decoder, wholeMsgMethodHandle);
metadata.sinkClass = messageSink.getClass();
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
this.textMetadata = metadata;
@ -487,7 +487,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
{
assertBasicTypeNotRegistered(OpCode.TEXT, this.textMetadata, handler.getClass().getName());
Decoder.TextStream<T> decoder = availableDecoders.getInstanceOf(registeredDecoder);
MessageSink messageSink = new DecodedTextStreamMessageSink(session, decoder, wholeMsgMethodHandle);
MessageSink messageSink = new DecodedTextStreamMessageSink(coreSession, decoder, wholeMsgMethodHandle);
metadata.sinkClass = messageSink.getClass();
this.textSink = registerMessageHandler(OpCode.TEXT, clazz, handler, messageSink);
this.textMetadata = metadata;
@ -659,21 +659,11 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
this.upgradeRequest = upgradeRequest;
}
public void setUpgradeResponse(UpgradeResponse upgradeResponse)
{
this.upgradeResponse = upgradeResponse;
}
public UpgradeRequest getUpgradeRequest()
{
return upgradeRequest;
}
public UpgradeResponse getUpgradeResponse()
{
return upgradeResponse;
}
private void configListener(String key, Object value)
{
if (!key.startsWith("org.eclipse.jetty.websocket."))

View File

@ -43,23 +43,26 @@ import javax.websocket.PongMessage;
import javax.websocket.Session;
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.messages.ByteArrayMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.ByteBufferMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedBinaryStreamMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.InputStreamMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.PartialByteArrayMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.PartialByteBufferMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.PartialStringMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.ReaderMessageSink;
import org.eclipse.jetty.websocket.javax.common.messages.StringMessageSink;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.messages.ByteArrayMessageSink;
import org.eclipse.jetty.websocket.util.messages.ByteBufferMessageSink;
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialByteArrayMessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialByteBufferMessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialStringMessageSink;
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerMetadata.MessageMetadata;
@ -322,15 +325,15 @@ public abstract class JavaxWebSocketFrameHandlerFactory
if (DecodedMessageSink.class.isAssignableFrom(msgMetadata.sinkClass))
{
MethodHandle ctorHandle = MethodHandles.lookup().findConstructor(msgMetadata.sinkClass,
MethodType.methodType(void.class, JavaxWebSocketSession.class, msgMetadata.registeredDecoder.interfaceType, MethodHandle.class));
MethodType.methodType(void.class, CoreSession.class, msgMetadata.registeredDecoder.interfaceType, MethodHandle.class));
Decoder decoder = session.getDecoders().getInstanceOf(msgMetadata.registeredDecoder);
return (MessageSink)ctorHandle.invoke(session, decoder, msgMetadata.handle);
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), decoder, msgMetadata.handle);
}
else
{
MethodHandle ctorHandle = MethodHandles.lookup().findConstructor(msgMetadata.sinkClass,
MethodType.methodType(void.class, JavaxWebSocketSession.class, MethodHandle.class));
return (MessageSink)ctorHandle.invoke(session, msgMetadata.handle);
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class));
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.handle);
}
}
catch (NoSuchMethodException e)
@ -385,8 +388,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
protected JavaxWebSocketFrameHandlerMetadata createEndpointMetadata(Class<? extends javax.websocket.Endpoint> endpointClass, EndpointConfig endpointConfig)
{
JavaxWebSocketFrameHandlerMetadata metadata = new JavaxWebSocketFrameHandlerMetadata(endpointConfig);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass);
Method openMethod = ReflectUtils.findMethod(endpointClass, "onOpen",
javax.websocket.Session.class, javax.websocket.EndpointConfig.class);
@ -408,6 +410,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
protected JavaxWebSocketFrameHandlerMetadata discoverJavaxFrameHandlerMetadata(Class<?> endpointClass, JavaxWebSocketFrameHandlerMetadata metadata)
{
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass);
Method onmethod;
// OnOpen [0..1]
@ -418,7 +421,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
final InvokerUtils.Arg ENDPOINT_CONFIG = new InvokerUtils.Arg(EndpointConfig.class);
MethodHandle methodHandle = InvokerUtils
.mutatedInvoker(endpointClass, onmethod, paramIdentifier, metadata.getNamedTemplateVariables(), SESSION, ENDPOINT_CONFIG);
.mutatedInvoker(lookup, endpointClass, onmethod, paramIdentifier, metadata.getNamedTemplateVariables(), SESSION, ENDPOINT_CONFIG);
metadata.setOpenHandler(methodHandle, onmethod);
}
@ -430,7 +433,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
final InvokerUtils.Arg CLOSE_REASON = new InvokerUtils.Arg(CloseReason.class);
MethodHandle methodHandle = InvokerUtils
.mutatedInvoker(endpointClass, onmethod, paramIdentifier, metadata.getNamedTemplateVariables(), SESSION, CLOSE_REASON);
.mutatedInvoker(lookup, endpointClass, onmethod, paramIdentifier, metadata.getNamedTemplateVariables(), SESSION, CLOSE_REASON);
metadata.setCloseHandler(methodHandle, onmethod);
}
@ -442,7 +445,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
final InvokerUtils.Arg CAUSE = new InvokerUtils.Arg(Throwable.class).required();
MethodHandle methodHandle = InvokerUtils
.mutatedInvoker(endpointClass, onmethod, paramIdentifier, metadata.getNamedTemplateVariables(), SESSION, CAUSE);
.mutatedInvoker(lookup, endpointClass, onmethod, paramIdentifier, metadata.getNamedTemplateVariables(), SESSION, CAUSE);
metadata.setErrorHandler(methodHandle, onmethod);
}
@ -465,7 +468,7 @@ public abstract class JavaxWebSocketFrameHandlerFactory
// Function to search for matching MethodHandle for the endpointClass given a signature.
Function<InvokerUtils.Arg[], MethodHandle> getMethodHandle = (signature) ->
InvokerUtils.optionalMutatedInvoker(endpointClass, onMsg, paramIdentifier, metadata.getNamedTemplateVariables(), signature);
InvokerUtils.optionalMutatedInvoker(lookup, endpointClass, onMsg, paramIdentifier, metadata.getNamedTemplateVariables(), signature);
// Try to match from available decoders.
if (matchDecoders(onMsg, metadata, msgMetadata, getMethodHandle))
@ -701,6 +704,20 @@ public abstract class JavaxWebSocketFrameHandlerFactory
}
}
private MethodHandles.Lookup getMethodHandleLookup(Class<?> endpointClass) throws InvalidWebSocketException
{
MethodHandles.Lookup lookup;
try
{
lookup = MethodHandles.privateLookupIn(endpointClass, MethodHandles.lookup());
}
catch (IllegalAccessException e)
{
throw new InvalidWebSocketException("Unable to obtain MethodHandle lookup for " + endpointClass, e);
}
return lookup;
}
private static class DecodedArgs
{
public final AvailableDecoders.RegisteredDecoder registeredDecoder;

View File

@ -26,6 +26,8 @@ import javax.websocket.EndpointConfig;
import org.eclipse.jetty.http.pathmap.UriTemplatePathSpec;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
public class JavaxWebSocketFrameHandlerMetadata
{

View File

@ -36,8 +36,8 @@ import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.OutgoingFrames;
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
import org.eclipse.jetty.websocket.javax.common.messages.MessageOutputStream;
import org.eclipse.jetty.websocket.javax.common.messages.MessageWriter;
import org.eclipse.jetty.websocket.util.messages.MessageOutputStream;
import org.eclipse.jetty.websocket.util.messages.MessageWriter;
public class JavaxWebSocketRemoteEndpoint implements javax.websocket.RemoteEndpoint, OutgoingFrames
{
@ -56,12 +56,12 @@ public class JavaxWebSocketRemoteEndpoint implements javax.websocket.RemoteEndpo
protected MessageWriter newMessageWriter()
{
return new MessageWriter(coreSession, coreSession.getOutputBufferSize());
return new MessageWriter(coreSession, session.getContainerImpl().getBufferPool());
}
protected MessageOutputStream newMessageOutputStream()
{
return new MessageOutputStream(coreSession, coreSession.getOutputBufferSize(), session.getContainerImpl().getBufferPool());
return new MessageOutputStream(coreSession, session.getContainerImpl().getBufferPool());
}
@Override

View File

@ -46,7 +46,7 @@ import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.ReflectUtils;
/**
* Client Session for the JSR.

View File

@ -1,34 +0,0 @@
//
// ========================================================================
// 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.common;
import java.net.URI;
import java.util.List;
import java.util.Map;
public interface JavaxWebSocketUpgradeRequest
{
boolean isSecure();
Map<String, List<String>> getParameterMap();
String getProtocolVersion();
URI getRequestURI();
}

View File

@ -1,30 +0,0 @@
//
// ========================================================================
// 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.common;
import java.util.List;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
public interface JavaxWebSocketUpgradeResponse
{
String getAcceptedSubProtocol();
List<ExtensionConfig> getExtensions();
}

View File

@ -1,37 +0,0 @@
//
// ========================================================================
// 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.common;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.Frame;
/**
* Sink consumer for messages (used for multiple frames with continuations,
* and also to allow for streaming APIs)
*/
public interface MessageSink
{
/**
* Consume the frame payload to the message.
*
* @param frame the frame, its payload (and fin state) to append
* @param callback the callback for how the frame was consumed
*/
void accept(Frame frame, Callback callback);
}

View File

@ -23,11 +23,12 @@ import java.security.Principal;
public class UpgradeRequestAdapter implements UpgradeRequest
{
private URI requestURI;
private final URI requestURI;
public UpgradeRequestAdapter()
{
/* anonymous, no requestURI, upgrade request */
this(null);
}
public UpgradeRequestAdapter(URI uri)

View File

@ -1,30 +0,0 @@
//
// ========================================================================
// 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.common;
import java.util.List;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
public interface UpgradeResponse
{
String getAcceptedSubProtocol();
List<ExtensionConfig> getExtensions();
}

View File

@ -1,63 +0,0 @@
//
// ========================================================================
// 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.common;
import java.util.Collections;
import java.util.List;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
public class UpgradeResponseAdapter implements UpgradeResponse
{
private final String acceptedSubProtocol;
private final List<ExtensionConfig> extensions;
public UpgradeResponseAdapter()
{
this(null, Collections.emptyList());
}
public UpgradeResponseAdapter(String acceptedSubProtocol, List<ExtensionConfig> extensions)
{
this.acceptedSubProtocol = acceptedSubProtocol;
this.extensions = extensions;
}
/**
* Get the accepted WebSocket protocol.
*
* @return the accepted WebSocket protocol.
*/
@Override
public String getAcceptedSubProtocol()
{
return acceptedSubProtocol;
}
/**
* Get the list of extensions that should be used for the websocket.
*
* @return the list of negotiated extensions to use.
*/
@Override
public List<ExtensionConfig> getExtensions()
{
return extensions;
}
}

View File

@ -32,9 +32,9 @@ import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.javax.common.InitException;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.eclipse.jetty.websocket.util.ReflectUtils;
public class AvailableDecoders implements Iterable<AvailableDecoders.RegisteredDecoder>
{

View File

@ -39,10 +39,6 @@ public class BooleanDecoder extends AbstractDecoder implements Decoder.Text<Bool
@Override
public boolean willDecode(String s)
{
if (s == null)
{
return false;
}
return true;
return (s != null);
}
}

View File

@ -30,9 +30,9 @@ import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.javax.common.InitException;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.eclipse.jetty.websocket.util.ReflectUtils;
public class AvailableEncoders implements Predicate<Class<?>>
{
@ -289,9 +289,6 @@ public class AvailableEncoders implements Predicate<Class<?>>
@Override
public boolean test(Class<?> type)
{
return registeredEncoders.stream()
.filter(registered -> registered.isType(type))
.findFirst()
.isPresent();
return registeredEncoders.stream().anyMatch(registered -> registered.isType(type));
}
}

View File

@ -1,90 +0,0 @@
//
// ========================================================================
// 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.common.messages;
import java.io.ByteArrayOutputStream;
import java.lang.invoke.MethodHandle;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
public class ByteBufferMessageSink extends AbstractMessageSink
{
private static final int BUFFER_SIZE = 65535;
private ByteArrayOutputStream out;
private int size;
public ByteBufferMessageSink(JavaxWebSocketSession session, MethodHandle methodHandle)
{
super(session, methodHandle);
}
@SuppressWarnings("Duplicates")
@Override
public void accept(Frame frame, Callback callback)
{
try
{
if (frame.hasPayload())
{
ByteBuffer payload = frame.getPayload();
size += payload.remaining();
if (session.getMaxBinaryMessageBufferSize() > 0 && size > session.getMaxBinaryMessageBufferSize())
{
throw new MessageTooLargeException(String.format("Binary message too large: (actual) %,d > (configured max binary buffer size) %,d",
size, session.getMaxBinaryMessageBufferSize()));
}
if (out == null)
out = new ByteArrayOutputStream(BUFFER_SIZE);
BufferUtil.writeTo(payload, out);
payload.position(payload.limit()); // consume buffer
}
if (frame.isFin())
{
if (out != null)
methodHandle.invoke(ByteBuffer.wrap(out.toByteArray()));
else
methodHandle.invoke(BufferUtil.EMPTY_BUFFER);
}
callback.succeeded();
}
catch (Throwable t)
{
callback.failed(t);
}
finally
{
if (frame.isFin())
{
// reset
out = null;
size = 0;
}
}
}
}

View File

@ -26,13 +26,14 @@ import javax.websocket.CloseReason;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.exception.CloseException;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.MessageSink;
import org.eclipse.jetty.websocket.util.messages.ByteBufferMessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
public class DecodedBinaryMessageSink<T> extends DecodedMessageSink<Decoder.Binary<T>>
{
public DecodedBinaryMessageSink(JavaxWebSocketSession session,
public DecodedBinaryMessageSink(CoreSession session,
Decoder.Binary<T> decoder,
MethodHandle methodHandle)
throws NoSuchMethodException, IllegalAccessException
@ -49,7 +50,7 @@ public class DecodedBinaryMessageSink<T> extends DecodedMessageSink<Decoder.Bina
}
@Override
protected MessageSink newRawMessageSink(JavaxWebSocketSession session, MethodHandle rawMethodHandle)
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
{
return new ByteBufferMessageSink(session, rawMethodHandle);
}

View File

@ -26,13 +26,14 @@ import javax.websocket.CloseReason;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.exception.CloseException;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.MessageSink;
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
public class DecodedBinaryStreamMessageSink<T> extends DecodedMessageSink<Decoder.BinaryStream<T>>
{
public DecodedBinaryStreamMessageSink(JavaxWebSocketSession session,
public DecodedBinaryStreamMessageSink(CoreSession session,
Decoder.BinaryStream<T> decoder,
MethodHandle methodHandle)
throws NoSuchMethodException, IllegalAccessException
@ -49,7 +50,7 @@ public class DecodedBinaryStreamMessageSink<T> extends DecodedMessageSink<Decode
}
@Override
protected MessageSink newRawMessageSink(JavaxWebSocketSession session, MethodHandle rawMethodHandle)
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
{
return new InputStreamMessageSink(session, rawMethodHandle);
}

View File

@ -24,9 +24,10 @@ import javax.websocket.Decoder;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.MessageSink;
import org.eclipse.jetty.websocket.util.messages.AbstractMessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
public abstract class DecodedMessageSink<T extends Decoder> extends AbstractMessageSink
{
@ -35,7 +36,7 @@ public abstract class DecodedMessageSink<T extends Decoder> extends AbstractMess
private final MethodHandle rawMethodHandle;
private final MessageSink rawMessageSink;
public DecodedMessageSink(JavaxWebSocketSession session, T decoder, MethodHandle methodHandle)
public DecodedMessageSink(CoreSession session, T decoder, MethodHandle methodHandle)
throws NoSuchMethodException, IllegalAccessException
{
super(session, methodHandle);
@ -48,7 +49,7 @@ public abstract class DecodedMessageSink<T extends Decoder> extends AbstractMess
protected abstract MethodHandle newRawMethodHandle()
throws NoSuchMethodException, IllegalAccessException;
protected abstract MessageSink newRawMessageSink(JavaxWebSocketSession session, MethodHandle rawMethodHandle);
protected abstract MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle);
public T getDecoder()
{

View File

@ -25,13 +25,14 @@ import javax.websocket.CloseReason;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.exception.CloseException;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.MessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
public class DecodedTextMessageSink<T> extends DecodedMessageSink<Decoder.Text<T>>
{
public DecodedTextMessageSink(JavaxWebSocketSession session,
public DecodedTextMessageSink(CoreSession session,
Decoder.Text<T> decoder,
MethodHandle methodHandle)
throws NoSuchMethodException, IllegalAccessException
@ -48,7 +49,7 @@ public class DecodedTextMessageSink<T> extends DecodedMessageSink<Decoder.Text<T
}
@Override
protected MessageSink newRawMessageSink(JavaxWebSocketSession session, MethodHandle rawMethodHandle)
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
{
return new StringMessageSink(session, rawMethodHandle);
}

View File

@ -26,13 +26,14 @@ import javax.websocket.CloseReason;
import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.exception.CloseException;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.MessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
public class DecodedTextStreamMessageSink<T> extends DecodedMessageSink<Decoder.TextStream<T>>
{
public DecodedTextStreamMessageSink(JavaxWebSocketSession session,
public DecodedTextStreamMessageSink(CoreSession session,
Decoder.TextStream<T> decoder,
MethodHandle methodHandle)
throws NoSuchMethodException, IllegalAccessException
@ -49,7 +50,7 @@ public class DecodedTextStreamMessageSink<T> extends DecodedMessageSink<Decoder.
}
@Override
protected MessageSink newRawMessageSink(JavaxWebSocketSession session, MethodHandle rawMethodHandle)
protected MessageSink newRawMessageSink(CoreSession session, MethodHandle rawMethodHandle)
{
return new ReaderMessageSink(session, rawMethodHandle);
}

View File

@ -1,48 +0,0 @@
//
// ========================================================================
// 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.common.messages;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.javax.common.MessageSink;
/**
* Support class for reading a (single) WebSocket TEXT message via a Reader.
* <p>
* In compliance to the WebSocket spec, this reader always uses the {@link StandardCharsets#UTF_8}.
*/
public class MessageReader extends InputStreamReader implements MessageSink
{
private final MessageInputStream stream;
public MessageReader(MessageInputStream stream)
{
super(stream, StandardCharsets.UTF_8);
this.stream = stream;
}
@Override
public void accept(Frame frame, Callback callback)
{
this.stream.accept(frame, callback);
}
}

View File

@ -1,56 +0,0 @@
//
// ========================================================================
// 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.common.util;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
@SuppressWarnings("serial")
public class DuplicateAnnotationException extends InvalidWebSocketException
{
public static DuplicateAnnotationException build(Class<?> pojo, Class<? extends Annotation> annoClass, Method... methods)
{
// Build big detailed exception to help the developer
StringBuilder err = new StringBuilder();
err.append("Duplicate @");
err.append(annoClass.getSimpleName());
err.append(" declarations in: ");
err.append(pojo.getName());
for (Method method : methods)
{
err.append(System.lineSeparator());
ReflectUtils.append(err, method);
}
return new DuplicateAnnotationException(err.toString());
}
public DuplicateAnnotationException(String message)
{
super(message);
}
public DuplicateAnnotationException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -1,562 +0,0 @@
//
// ========================================================================
// 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.common.util;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
public class ReflectUtils
{
private static final Pattern JAVAX_CLASSNAME_PATTERN = Pattern.compile("^javax*\\..*");
private static class GenericRef
{
// The base class reference lookup started from
private final Class<?> baseClass;
// The interface that we are interested in
private final Class<?> ifaceClass;
// The actual class generic interface was found on
Class<?> genericClass;
// The found genericType
public Type genericType;
private int genericIndex;
public GenericRef(final Class<?> baseClass, final Class<?> ifaceClass)
{
this.baseClass = baseClass;
this.ifaceClass = ifaceClass;
}
public boolean needsUnwrap()
{
return (genericClass == null) && (genericType != null) && (genericType instanceof TypeVariable<?>);
}
public void setGenericFromType(Type type, int index)
{
// debug("setGenericFromType(%s,%d)",toShortName(type),index);
this.genericType = type;
this.genericIndex = index;
if (type instanceof Class)
{
this.genericClass = (Class<?>)type;
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("GenericRef [baseClass=");
builder.append(baseClass);
builder.append(", ifaceClass=");
builder.append(ifaceClass);
builder.append(", genericType=");
builder.append(genericType);
builder.append(", genericClass=");
builder.append(genericClass);
builder.append("]");
return builder.toString();
}
}
private static StringBuilder appendTypeName(StringBuilder sb, Type type, boolean ellipses)
{
if (type instanceof Class<?>)
{
Class<?> ctype = (Class<?>)type;
if (ctype.isArray())
{
try
{
int dimensions = 0;
while (ctype.isArray())
{
dimensions++;
ctype = ctype.getComponentType();
}
sb.append(ctype.getName());
for (int i = 0; i < dimensions; i++)
{
if (ellipses)
{
sb.append("...");
}
else
{
sb.append("[]");
}
}
return sb;
}
catch (Throwable ignore)
{
// ignore
}
}
sb.append(ctype.getName());
}
else
{
sb.append(type.toString());
}
return sb;
}
public static void assertIsAnnotated(Method method, Class<? extends Annotation> annoClass)
{
if (method.getAnnotation(annoClass) == null)
{
StringBuilder err = new StringBuilder();
err.append("Method does not declare required @");
err.append(annoClass.getName());
err.append(" annotation: ");
err.append(method);
throw new InvalidWebSocketException(err.toString());
}
}
public static void assertIsPublicNonStatic(Method method)
{
int mods = method.getModifiers();
if (!Modifier.isPublic(mods))
{
StringBuilder err = new StringBuilder();
err.append("Invalid declaration of ");
err.append(method);
err.append(System.lineSeparator());
err.append("Method modifier must be public");
throw new InvalidWebSocketException(err.toString());
}
if (Modifier.isStatic(mods))
{
StringBuilder err = new StringBuilder();
err.append("Invalid declaration of ");
err.append(method);
err.append(System.lineSeparator());
err.append("Method modifier must not be static");
throw new InvalidWebSocketException(err.toString());
}
}
public static void assertIsReturn(Method method, Class<?> type)
{
if (!type.equals(method.getReturnType()))
{
StringBuilder err = new StringBuilder();
err.append("Invalid declaration of ");
err.append(method);
err.append(System.lineSeparator());
err.append("Return type must be ").append(type);
throw new InvalidWebSocketException(err.toString());
}
}
public static Method findMethod(Class<?> pojo, String methodName, Class<?>... params)
{
try
{
return pojo.getMethod(methodName, params);
}
catch (NoSuchMethodException e)
{
return null;
}
}
public static Method findAnnotatedMethod(Class<?> pojo, Class<? extends Annotation> anno)
{
Method[] methods = findAnnotatedMethods(pojo, anno);
if (methods == null)
{
return null;
}
if (methods.length > 1)
{
throw DuplicateAnnotationException.build(pojo, anno, methods);
}
return methods[0];
}
public static Method[] findAnnotatedMethods(Class<?> pojo, Class<? extends Annotation> anno)
{
List<Method> methods = null;
Class<?> clazz = pojo;
while ((clazz != null) && Object.class.isAssignableFrom(clazz))
{
for (Method method : clazz.getDeclaredMethods())
{
if (method.getAnnotation(anno) != null)
{
if (methods == null)
methods = new ArrayList<>();
methods.add(method);
}
}
clazz = clazz.getSuperclass();
}
if (methods == null)
return null;
int len = methods.size();
return methods.toArray(new Method[len]);
}
/**
* Given a Base (concrete) Class, find the interface specified, and return its concrete Generic class declaration.
*
* @param baseClass the base (concrete) class to look in
* @param ifaceClass the interface of interest
* @return the (concrete) generic class that the interface exposes
*/
public static Class<?> findGenericClassFor(Class<?> baseClass, Class<?> ifaceClass)
{
GenericRef ref = new GenericRef(baseClass, ifaceClass);
if (resolveGenericRef(ref, baseClass))
{
// debug("Generic Found: %s",ref.genericClass);
return ref.genericClass;
}
// debug("Generic not found: %s",ref);
return null;
}
private static int findTypeParameterIndex(Class<?> clazz, TypeVariable<?> needVar)
{
// debug("findTypeParameterIndex(%s, [%s])",toShortName(clazz),toShortName(needVar));
TypeVariable<?>[] params = clazz.getTypeParameters();
for (int i = 0; i < params.length; i++)
{
if (params[i].getName().equals(needVar.getName()))
{
// debug("Type Parameter found at index: [%d]",i);
return i;
}
}
// debug("Type Parameter NOT found");
return -1;
}
public static boolean isDefaultConstructable(Class<?> clazz)
{
int mods = clazz.getModifiers();
if (Modifier.isAbstract(mods) || !Modifier.isPublic(mods))
{
// Needs to be public, non-abstract
return false;
}
Class<?>[] noargs = new Class<?>[0];
try
{
// Needs to have a no-args constructor
Constructor<?> constructor = clazz.getConstructor(noargs);
// Constructor needs to be public
return Modifier.isPublic(constructor.getModifiers());
}
catch (NoSuchMethodException | SecurityException e)
{
return false;
}
}
public static boolean isSameParameters(Class<?>[] actual, Class<?>[] params)
{
if (actual.length != params.length)
{
// skip
return false;
}
int len = params.length;
for (int i = 0; i < len; i++)
{
if (!actual[i].equals(params[i]))
{
return false; // not valid
}
}
return true;
}
private static boolean resolveGenericRef(GenericRef ref, Class<?> clazz, Type type)
{
if (type instanceof Class)
{
if (type == ref.ifaceClass)
{
// is this a straight ref or a TypeVariable?
// debug("Found ref (as class): %s",toShortName(type));
ref.setGenericFromType(type, 0);
return true;
}
else
{
// Keep digging
return resolveGenericRef(ref, type);
}
}
if (type instanceof ParameterizedType)
{
ParameterizedType ptype = (ParameterizedType)type;
Type rawType = ptype.getRawType();
if (rawType == ref.ifaceClass)
{
// debug("Found ref on [%s] as ParameterizedType [%s]",toShortName(clazz),toShortName(ptype));
// Always get the raw type parameter, let unwrap() solve for what it is
ref.setGenericFromType(ptype.getActualTypeArguments()[0], 0);
return true;
}
else
{
// Keep digging
return resolveGenericRef(ref, rawType);
}
}
return false;
}
private static boolean resolveGenericRef(GenericRef ref, Type type)
{
if ((type == null) || (type == Object.class))
{
return false;
}
if (type instanceof Class)
{
Class<?> clazz = (Class<?>)type;
// prevent spinning off into Serialization and other parts of the
// standard tree that we could care less about
if (JAVAX_CLASSNAME_PATTERN.matcher(clazz.getName()).matches())
{
return false;
}
Type[] ifaces = clazz.getGenericInterfaces();
for (Type iface : ifaces)
{
// debug("resolve %s interface[]: %s",toShortName(clazz),toShortName(iface));
if (resolveGenericRef(ref, clazz, iface))
{
if (ref.needsUnwrap())
{
// debug("## Unwrap class %s::%s",toShortName(clazz),toShortName(iface));
TypeVariable<?> needVar = (TypeVariable<?>)ref.genericType;
// debug("needs unwrap of type var [%s] - index [%d]",toShortName(needVar),ref.genericIndex);
// attempt to find typeParameter on class itself
int typeParamIdx = findTypeParameterIndex(clazz, needVar);
// debug("type param index for %s[%s] is [%d]",toShortName(clazz),toShortName(needVar),typeParamIdx);
if (typeParamIdx >= 0)
{
// found a type parameter, use it
// debug("unwrap from class [%s] - typeParameters[%d]",toShortName(clazz),typeParamIdx);
TypeVariable<?>[] params = clazz.getTypeParameters();
if (params.length >= typeParamIdx)
{
ref.setGenericFromType(params[typeParamIdx], typeParamIdx);
}
}
else if (iface instanceof ParameterizedType)
{
// use actual args on interface
Type arg = ((ParameterizedType)iface).getActualTypeArguments()[ref.genericIndex];
ref.setGenericFromType(arg, ref.genericIndex);
}
}
return true;
}
}
type = clazz.getGenericSuperclass();
return resolveGenericRef(ref, type);
}
if (type instanceof ParameterizedType)
{
ParameterizedType ptype = (ParameterizedType)type;
Class<?> rawClass = (Class<?>)ptype.getRawType();
if (resolveGenericRef(ref, rawClass))
{
if (ref.needsUnwrap())
{
// debug("## Unwrap ParameterizedType %s::%s",toShortName(type),toShortName(rawClass));
TypeVariable<?> needVar = (TypeVariable<?>)ref.genericType;
// debug("needs unwrap of type var [%s] - index [%d]",toShortName(needVar),ref.genericIndex);
int typeParamIdx = findTypeParameterIndex(rawClass, needVar);
// debug("type paramIdx of %s::%s is index [%d]",toShortName(rawClass),toShortName(needVar),typeParamIdx);
Type arg = ptype.getActualTypeArguments()[typeParamIdx];
ref.setGenericFromType(arg, typeParamIdx);
return true;
}
}
}
return false;
}
public static String toShortName(Type type)
{
if (type == null)
{
return "<null>";
}
if (type instanceof Class)
{
String name = ((Class<?>)type).getName();
return trimClassName(name);
}
if (type instanceof ParameterizedType)
{
ParameterizedType ptype = (ParameterizedType)type;
StringBuilder str = new StringBuilder();
str.append(trimClassName(((Class<?>)ptype.getRawType()).getName()));
str.append("<");
Type[] args = ptype.getActualTypeArguments();
for (int i = 0; i < args.length; i++)
{
if (i > 0)
{
str.append(",");
}
str.append(args[i]);
}
str.append(">");
return str.toString();
}
return type.toString();
}
public static String toString(Class<?> pojo, Method method)
{
StringBuilder str = new StringBuilder();
append(str, pojo, method);
return str.toString();
}
public static String trimClassName(String name)
{
int idx = name.lastIndexOf('.');
name = name.substring(idx + 1);
idx = name.lastIndexOf('$');
if (idx >= 0)
{
name = name.substring(idx + 1);
}
return name;
}
public static void append(StringBuilder str, Class<?> pojo, Method method)
{
// method modifiers
int mod = method.getModifiers() & Modifier.methodModifiers();
if (mod != 0)
{
str.append(Modifier.toString(mod)).append(' ');
}
// return type
Type retType = method.getGenericReturnType();
appendTypeName(str, retType, false).append(' ');
if (pojo != null)
{
// class name
str.append(pojo.getName());
str.append("#");
}
// method name
str.append(method.getName());
// method parameters
str.append('(');
Type[] params = method.getGenericParameterTypes();
for (int j = 0; j < params.length; j++)
{
boolean ellipses = method.isVarArgs() && (j == (params.length - 1));
appendTypeName(str, params[j], ellipses);
if (j < (params.length - 1))
{
str.append(", ");
}
}
str.append(')');
// TODO: show exceptions?
}
public static void append(StringBuilder str, Method method)
{
append(str, null, method);
}
public static void append(StringBuilder str, MethodType methodType)
{
str.append(methodType.returnType().getName());
str.append("(");
boolean delim = false;
for (Class<?> paramType : methodType.parameterList())
{
if (delim)
str.append(", ");
str.append(paramType.getName());
delim = true;
}
str.append(")");
}
}

View File

@ -1,97 +0,0 @@
//
// ========================================================================
// 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.common.util;
/**
* Collection of utility methods for Text content
*/
public final class TextUtil
{
/**
* Create a hint of what the text is like.
* <p>
* Used by logging and error messages to get a hint of what the text is like.
*
* @param text the text to abbreviate, quote, and generally give you a hint of what the value is.
* @return the abbreviated text
*/
public static String quote(String text)
{
if (text == null)
{
return "<null>";
}
return '"' + text + '"';
}
/**
* Create a hint of what the text is like.
* <p>
* Used by logging and error messages to get a hint of what the text is like.
*
* @param text the text to abbreviate, quote, and generally give you a hint of what the value is.
* @return the abbreviated text
*/
public static String hint(String text)
{
if (text == null)
{
return "<null>";
}
return '"' + maxStringLength(30, text) + '"';
}
/**
* Smash a long string to fit within the max string length, by taking the middle section of the string and replacing them with an ellipsis "..."
*
* <pre>
* Examples:
* .maxStringLength( 9, "Eatagramovabits") == "Eat...its"
* .maxStringLength(10, "Eatagramovabits") == "Eat...bits"
* .maxStringLength(11, "Eatagramovabits") == "Eata...bits"
* </pre>
*
* @param max the maximum size of the string (minimum size supported is 9)
* @param raw the raw string to smash
* @return the ellipsis'd version of the string.
*/
public static String maxStringLength(int max, String raw)
{
int length = raw.length();
if (length <= max)
{
// already short enough
return raw;
}
if (max < 9)
{
// minimum supported
return raw.substring(0, max);
}
StringBuilder ret = new StringBuilder();
int startLen = (int)Math.round((double)max / (double)3);
ret.append(raw.substring(0, startLen));
ret.append("...");
ret.append(raw.substring(length - (max - startLen - 3)));
return ret.toString();
}
}

View File

@ -23,7 +23,7 @@ import javax.websocket.ClientEndpointConfig;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.InvokerUtils;
public class DummyFrameHandlerFactory extends JavaxWebSocketFrameHandlerFactory
{

View File

@ -25,7 +25,7 @@ import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;

View File

@ -30,7 +30,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.sockets.TrackingSocket;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;

View File

@ -30,7 +30,7 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.sockets.TrackingSocket;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.Test;

View File

@ -30,10 +30,10 @@ import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -50,9 +50,9 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
Decoder.Binary<Calendar> decoder = new GmtDecoder();
DecodedBinaryMessageSink sink = new DecodedBinaryMessageSink(AbstractSessionTest.session, decoder, copyHandle);
DecodedBinaryMessageSink sink = new DecodedBinaryMessageSink(AbstractSessionTest.session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback finCallback = new FutureCallback();
ByteBuffer data = ByteBuffer.allocate(16);
data.putShort((short)1999);
data.put((byte)12);
@ -73,11 +73,11 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
Decoder.Binary<Calendar> decoder = new GmtDecoder();
DecodedBinaryMessageSink sink = new DecodedBinaryMessageSink(AbstractSessionTest.session, decoder, copyHandle);
DecodedBinaryMessageSink sink = new DecodedBinaryMessageSink(AbstractSessionTest.session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
ByteBuffer data1 = ByteBuffer.allocate(16);
data1.putShort((short)2000);

View File

@ -33,9 +33,9 @@ import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -52,9 +52,9 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
Decoder.BinaryStream<Calendar> decoder = new GmtDecoder();
DecodedBinaryStreamMessageSink sink = new DecodedBinaryStreamMessageSink(session, decoder, copyHandle);
DecodedBinaryStreamMessageSink sink = new DecodedBinaryStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback finCallback = new FutureCallback();
ByteBuffer data = ByteBuffer.allocate(16);
data.putShort((short)1999);
data.put((byte)12);
@ -75,11 +75,11 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
Decoder.BinaryStream<Calendar> decoder = new GmtDecoder();
DecodedBinaryStreamMessageSink sink = new DecodedBinaryStreamMessageSink(session, decoder, copyHandle);
DecodedBinaryStreamMessageSink sink = new DecodedBinaryStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
ByteBuffer data1 = ByteBuffer.allocate(16);
data1.putShort((short)2000);

View File

@ -30,9 +30,9 @@ import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -49,9 +49,9 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
Decoder.Text<Date> decoder = new GmtDecoder();
DecodedTextMessageSink sink = new DecodedTextMessageSink(session, decoder, copyHandle);
DecodedTextMessageSink sink = new DecodedTextMessageSink(session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
finCallback.get(1, TimeUnit.SECONDS); // wait for callback
@ -67,11 +67,11 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
Decoder.Text<Date> decoder = new GmtDecoder();
DecodedTextMessageSink sink = new DecodedTextMessageSink(session, decoder, copyHandle);
DecodedTextMessageSink sink = new DecodedTextMessageSink(session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.TEXT).setPayload("2023").setFin(false), callback1);
sink.accept(new Frame(OpCode.CONTINUATION).setPayload(".08").setFin(false), callback2);

View File

@ -32,10 +32,10 @@ import javax.websocket.DecodeException;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -52,9 +52,9 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
Decoder.TextStream<Date> decoder = new GmtDecoder();
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session, decoder, copyHandle);
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
finCallback.get(1, TimeUnit.SECONDS); // wait for callback
@ -70,11 +70,11 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
Decoder.TextStream<Date> decoder = new GmtDecoder();
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session, decoder, copyHandle);
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session.getCoreSession(), decoder, copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.TEXT).setPayload("2023").setFin(false), callback1);
sink.accept(new Frame(OpCode.CONTINUATION).setPayload(".08").setFin(false), callback2);

View File

@ -31,11 +31,12 @@ import java.util.function.Consumer;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.AbstractSessionTest;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
import org.junit.jupiter.api.Test;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -49,9 +50,9 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
{
InputStreamCopy copy = new InputStreamCopy();
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session, copyHandle);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle);
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback finCallback = new FutureCallback();
ByteBuffer data = BufferUtil.toBuffer("Hello World", UTF_8);
sink.accept(new Frame(OpCode.BINARY).setPayload(data), finCallback);
@ -66,9 +67,9 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
{
InputStreamCopy copy = new InputStreamCopy();
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session, copyHandle);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle);
CompletableFutureCallback fin1Callback = new CompletableFutureCallback();
FutureCallback fin1Callback = new FutureCallback();
ByteBuffer data1 = BufferUtil.toBuffer("Hello World", UTF_8);
sink.accept(new Frame(OpCode.BINARY).setPayload(data1).setFin(true), fin1Callback);
@ -77,7 +78,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
assertThat("FinCallback.done", fin1Callback.isDone(), is(true));
assertThat("Writer.contents", new String(byteStream.toByteArray(), UTF_8), is("Hello World"));
CompletableFutureCallback fin2Callback = new CompletableFutureCallback();
FutureCallback fin2Callback = new FutureCallback();
ByteBuffer data2 = BufferUtil.toBuffer("Greetings Earthling", UTF_8);
sink.accept(new Frame(OpCode.BINARY).setPayload(data2).setFin(true), fin2Callback);
@ -92,11 +93,11 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
{
InputStreamCopy copy = new InputStreamCopy();
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session, copyHandle);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.BINARY).setPayload("Hello").setFin(false), callback1);
sink.accept(new Frame(OpCode.CONTINUATION).setPayload(", ").setFin(false), callback2);
@ -116,12 +117,12 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
{
InputStreamCopy copy = new InputStreamCopy();
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session, copyHandle);
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback callback3 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback callback3 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.BINARY).setPayload("Greetings").setFin(false), callback1);
sink.accept(new Frame(OpCode.CONTINUATION).setPayload(", ").setFin(false), callback2);

View File

@ -24,11 +24,14 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.MappedByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.util.messages.MessageWriter;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -36,11 +39,14 @@ import static org.hamcrest.Matchers.is;
public class MessageWriterTest
{
private ByteBufferPool bufferPool = new MappedByteBufferPool();
@Test
public void testSingleByteArray512b() throws IOException, InterruptedException
{
FrameCapture capture = new FrameCapture();
try (MessageWriter writer = new MessageWriter(capture, 1024))
capture.setOutputBufferSize(1024);
try (MessageWriter writer = new MessageWriter(capture, bufferPool))
{
char[] cbuf = new char[512];
Arrays.fill(cbuf, 'x');
@ -57,7 +63,8 @@ public class MessageWriterTest
public void testSingleByteArray2k() throws IOException, InterruptedException
{
FrameCapture capture = new FrameCapture();
try (MessageWriter writer = new MessageWriter(capture, 1024))
capture.setOutputBufferSize(1024);
try (MessageWriter writer = new MessageWriter(capture, bufferPool))
{
char[] cbuf = new char[1024 * 2];
Arrays.fill(cbuf, 'x');
@ -83,7 +90,8 @@ public class MessageWriterTest
final int writerBufferSize = 100;
FrameCapture capture = new FrameCapture();
try (MessageWriter writer = new MessageWriter(capture, writerBufferSize))
capture.setOutputBufferSize(writerBufferSize);
try (MessageWriter writer = new MessageWriter(capture, bufferPool))
{
char[] cbuf = new char[testSize];
Arrays.fill(cbuf, 'x');
@ -125,7 +133,8 @@ public class MessageWriterTest
final int testSize = writerBufferSize + 16;
WholeMessageCapture capture = new WholeMessageCapture();
try (MessageWriter writer = new MessageWriter(capture, writerBufferSize))
capture.setOutputBufferSize(writerBufferSize);
try (MessageWriter writer = new MessageWriter(capture, bufferPool))
{
char[] cbuf = new char[testSize];
Arrays.fill(cbuf, 'x');
@ -163,7 +172,7 @@ public class MessageWriterTest
if (frame.getOpCode() == OpCode.TEXT)
activeMessage = new Utf8StringBuilder();
activeMessage.append(frame.getPayload());
activeMessage.append(frame.getPayload().slice());
if (frame.isFin())
{

View File

@ -28,10 +28,11 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -45,9 +46,9 @@ public class ReaderMessageSinkTest extends AbstractMessageSinkTest
CompletableFuture<StringWriter> copyFuture = new CompletableFuture<>();
ReaderCopy copy = new ReaderCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Reader.class);
ReaderMessageSink sink = new ReaderMessageSink(session, copyHandle);
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), copyHandle);
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.TEXT).setPayload("Hello World"), finCallback);
finCallback.get(1, TimeUnit.SECONDS); // wait for callback
@ -62,11 +63,11 @@ public class ReaderMessageSinkTest extends AbstractMessageSinkTest
CompletableFuture<StringWriter> copyFuture = new CompletableFuture<>();
ReaderCopy copy = new ReaderCopy(copyFuture);
MethodHandle copyHandle = getAcceptHandle(copy, Reader.class);
ReaderMessageSink sink = new ReaderMessageSink(session, copyHandle);
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), copyHandle);
CompletableFutureCallback callback1 = new CompletableFutureCallback();
CompletableFutureCallback callback2 = new CompletableFutureCallback();
CompletableFutureCallback finCallback = new CompletableFutureCallback();
FutureCallback callback1 = new FutureCallback();
FutureCallback callback2 = new FutureCallback();
FutureCallback finCallback = new FutureCallback();
sink.accept(new Frame(OpCode.TEXT).setPayload("Hello").setFin(false), callback1);
sink.accept(new Frame(OpCode.CONTINUATION).setPayload(", ").setFin(false), callback2);

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.websocket.javax.common.util;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@ -26,7 +27,8 @@ import javax.websocket.Session;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketFrameHandlerFactory;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils.Arg;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.ReflectUtils;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -57,6 +59,8 @@ public class InvokerUtilsStaticParamsTest
return String.format("onColorMessage(%s, '%s', '%s')", color);
}
}
private static MethodHandles.Lookup lookup = MethodHandles.lookup();
@Test
public void testOnlyParamString() throws Throwable
@ -71,7 +75,7 @@ public class InvokerUtilsStaticParamsTest
// Raw Calling Args - none specified
// Get basic method handle (without a instance to call against) - this is what the metadata stores
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(Foo.class, method, new NameParamIdentifier(), namedVariables);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
// Some point later an actual instance is needed, which has static named parameters
Map<String, String> templateValues = new HashMap<>();
@ -100,7 +104,7 @@ public class InvokerUtilsStaticParamsTest
};
// Get basic method handle (without a instance to call against) - this is what the metadata stores
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(Foo.class, method, new NameParamIdentifier(), namedVariables);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
// Some point later an actual instance is needed, which has static named parameters
Map<String, String> templateValues = new HashMap<>();
@ -128,10 +132,10 @@ public class InvokerUtilsStaticParamsTest
"count"
};
final Arg ARG_LABEL = new Arg(String.class).required();
final InvokerUtils.Arg ARG_LABEL = new InvokerUtils.Arg(String.class).required();
// Get basic method handle (without a instance to call against) - this is what the metadata stores
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(Foo.class, method, new NameParamIdentifier(), namedVariables, ARG_LABEL);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, ARG_LABEL);
// Some point later an actual instance is needed, which has static named parameters
Map<String, String> templateValues = new HashMap<>();

View File

@ -20,9 +20,12 @@ package org.eclipse.jetty.websocket.javax.common.util;
import java.io.File;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.ReflectUtils;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -149,11 +152,13 @@ public class InvokerUtilsTest
throw new AssertionError("Unable to find method: " + name);
}
private static MethodHandles.Lookup lookup = MethodHandles.lookup();
@Test
public void testSimpleInvoker() throws Throwable
{
Method method = ReflectUtils.findMethod(Simple.class, "onMessage", String.class);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(Simple.class, method, new InvokerUtils.Arg(String.class));
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Simple.class, method, new InvokerUtils.Arg(String.class));
Simple simple = new Simple();
String result = (String)methodHandle.invoke(simple, "Hello World");
@ -170,7 +175,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(int.class)
};
MethodHandle methodHandle2 = InvokerUtils.mutatedInvoker(KeyValue.class, method2, callingArgs);
MethodHandle methodHandle2 = InvokerUtils.mutatedInvoker(lookup, KeyValue.class, method2, callingArgs);
KeyValue obj = new KeyValue();
String result = (String)methodHandle2.invoke(obj, "Year", 1972);
@ -187,7 +192,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(int.class)
};
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(KeyValue.class, method1, callingArgs);
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(lookup, KeyValue.class, method1, callingArgs);
KeyValue obj = new KeyValue();
String result = (String)methodHandle1.invoke(obj, "Age", 45);
@ -205,7 +210,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(Boolean.class)
};
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(KeyValue.class, method1, callingArgs);
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(lookup, KeyValue.class, method1, callingArgs);
KeyValue obj = new KeyValue();
String result = (String)methodHandle1.invoke(obj, "Age", 45, Boolean.TRUE);
@ -223,7 +228,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(int.class)
};
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(KeyValue.class, method1, callingArgs);
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(lookup, KeyValue.class, method1, callingArgs);
KeyValue obj = new KeyValue();
String result = (String)methodHandle1.invoke(obj, "Year", 888888L, 2017);
@ -241,7 +246,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(int.class)
};
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(KeyValue.class, method1, callingArgs);
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(lookup, KeyValue.class, method1, callingArgs);
KeyValue obj = new KeyValue();
String result = (String)methodHandle1.invoke(obj, new Simple(), "Count", 1776);
@ -261,7 +266,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(Long.class)
};
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(KeyValue.class, method1, callingArgs);
MethodHandle methodHandle1 = InvokerUtils.mutatedInvoker(lookup, KeyValue.class, method1, callingArgs);
KeyValue obj = new KeyValue();
String result = (String)methodHandle1.invoke(obj, new Simple(), "Amount", Boolean.TRUE, 200, 9999L);
@ -279,7 +284,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(int.class, "cost")
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(NamedParams.class, method, new NameParamIdentifier(), null, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, NamedParams.class, method, new NameParamIdentifier(), null, callingArgs);
NamedParams obj = new NamedParams();
String result = (String)methodHandle.invoke(obj, "Apple", "Red", 10);
@ -297,7 +302,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class, "color")
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(NamedParams.class, method, new NameParamIdentifier(), null, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, NamedParams.class, method, new NameParamIdentifier(), null, callingArgs);
NamedParams obj = new NamedParams();
String result = (String)methodHandle.invoke(obj, 20, "Banana", "Yellow");
@ -312,7 +317,7 @@ public class InvokerUtilsTest
InvokerUtils.Arg[] callingArgs = new InvokerUtils.Arg[]{};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples);
assertThat("Result", result, is("sigEmpty<>"));
}
@ -327,7 +332,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(File.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, new File("bogus"));
assertThat("Result", result, is("sigEmpty<>"));
}
@ -342,7 +347,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(File.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, null);
assertThat("Result", result, is("sigEmpty<>"));
}
@ -357,7 +362,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, "Hello");
assertThat("Result", result, is("sigStr<Hello>"));
}
@ -373,7 +378,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, new File("bogus"), "Hiya");
assertThat("Result", result, is("sigStr<Hiya>"));
}
@ -389,7 +394,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(File.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, "Greetings", new File("bogus"));
assertThat("Result", result, is("sigStr<Greetings>"));
}
@ -405,7 +410,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(File.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, "Name", new File("bogus1"));
assertThat("Result", result, is("sigStrFile<Name,bogus1>"));
}
@ -421,7 +426,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, new File("bogus2"), "Alt");
assertThat("Result", result, is("sigStrFile<Alt,bogus2>"));
}
@ -437,7 +442,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(File.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, "Bob", new File("bogus3"));
assertThat("Result", result, is("sigFileStr<bogus3,Bob>"));
}
@ -453,7 +458,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, new File("bogus4"), "Dobalina");
assertThat("Result", result, is("sigFileStr<bogus4,Dobalina>"));
}
@ -470,7 +475,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(boolean.class, "fin")
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, new NameParamIdentifier(), null, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, new NameParamIdentifier(), null, callingArgs);
String result = (String)methodHandle.invoke(samples, new File("foo"), "bar", true);
assertThat("Result", result, is("sigFileStrFin<foo,bar,true>"));
}
@ -487,7 +492,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(boolean.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, new File("baz"), "flem", false);
assertThat("Result", result, is("sigFileStrFin<baz,flem,false>"));
}
@ -504,7 +509,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, new NameParamIdentifier(), null, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, new NameParamIdentifier(), null, callingArgs);
String result = (String)methodHandle.invoke(samples, false, new File("foo"), "bar");
assertThat("Result", result, is("sigFileStrFin<foo,bar,false>"));
}
@ -521,7 +526,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, callingArgs);
String result = (String)methodHandle.invoke(samples, true, new File("foo"), "bar");
assertThat("Result", result, is("sigFileStrFin<foo,bar,true>"));
}
@ -538,7 +543,7 @@ public class InvokerUtilsTest
new InvokerUtils.Arg(String.class)
};
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(SampleSignatures.class, method, new NameParamIdentifier(), null, callingArgs);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, SampleSignatures.class, method, new NameParamIdentifier(), null, callingArgs);
String result = (String)methodHandle.invoke(samples, true, null, "bar");
assertThat("Result", result, is("sigFileStrFin<<null>,bar,true>"));
}

View File

@ -22,6 +22,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.websocket.util.InvokerUtils;
/**
* Simple {@link InvokerUtils.ParamIdentifier}

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.websocket.javax.common.util;
import org.eclipse.jetty.websocket.util.ReflectUtils;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;

View File

@ -12,6 +12,7 @@ annotations
[lib]
lib/websocket/websocket-core-${jetty.version}.jar
lib/websocket/websocket-util-${jetty.version}.jar
lib/websocket/websocket-servlet-${jetty.version}.jar
lib/websocket/jetty-javax-websocket-api-1.1.2.jar
lib/websocket/websocket-javax-*.jar

View File

@ -24,11 +24,11 @@ import java.security.Principal;
import org.eclipse.jetty.websocket.javax.common.UpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
public class DelegatedJavaxServletUpgradeRequest implements UpgradeRequest
public class JavaxServerUpgradeRequest implements UpgradeRequest
{
private final ServletUpgradeRequest servletRequest;
public DelegatedJavaxServletUpgradeRequest(ServletUpgradeRequest servletRequest)
public JavaxServerUpgradeRequest(ServletUpgradeRequest servletRequest)
{
this.servletRequest = servletRequest;
}

View File

@ -61,6 +61,6 @@ public class JavaxWebSocketServerFrameHandlerFactory extends JavaxWebSocketClien
@Override
public FrameHandler newFrameHandler(Object websocketPojo, ServletUpgradeRequest upgradeRequest, ServletUpgradeResponse upgradeResponse)
{
return newJavaxWebSocketFrameHandler(websocketPojo, new DelegatedJavaxServletUpgradeRequest(upgradeRequest));
return newJavaxWebSocketFrameHandler(websocketPojo, new JavaxServerUpgradeRequest(upgradeRequest));
}
}

View File

@ -22,7 +22,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import javax.websocket.server.PathParam;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.InvokerUtils;
/**
* Method argument identifier for {@link javax.websocket.server.PathParam} annotations.

View File

@ -1,47 +0,0 @@
//
// ========================================================================
// 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.server.internal;
import java.util.List;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.javax.common.UpgradeResponse;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
public class UpgradeResponseAdapter implements UpgradeResponse
{
private final ServletUpgradeResponse servletResponse;
public UpgradeResponseAdapter(ServletUpgradeResponse servletResponse)
{
this.servletResponse = servletResponse;
}
@Override
public String getAcceptedSubProtocol()
{
return this.servletResponse.getAcceptedSubProtocol();
}
@Override
public List<ExtensionConfig> getExtensions()
{
return this.servletResponse.getExtensions();
}
}

View File

@ -19,18 +19,19 @@
package org.eclipse.jetty.websocket.javax.tests;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.websocket.javax.common.util.InvokerUtils;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.ReflectUtils;
public class CompletableFutureMethodHandle
{
public static <T> MethodHandle of(Class<T> type, CompletableFuture<T> future)
{
Method method = ReflectUtils.findMethod(CompletableFuture.class, "complete", type);
MethodHandle completeHandle = InvokerUtils.mutatedInvoker(CompletableFuture.class, method, new InvokerUtils.Arg(type));
MethodHandle completeHandle = InvokerUtils.mutatedInvoker(MethodHandles.lookup(), CompletableFuture.class, method, new InvokerUtils.Arg(type));
return completeHandle.bindTo(future);
}
}

View File

@ -24,8 +24,8 @@ import javax.websocket.PongMessage;
import org.eclipse.jetty.websocket.javax.common.JavaxWebSocketSession;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.javax.tests.MessageType;
import org.eclipse.jetty.websocket.util.ReflectUtils;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;

View File

@ -47,9 +47,9 @@ import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.core.MessageHandler;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.core.server.Negotiation;
import org.eclipse.jetty.websocket.javax.common.util.TextUtil;
import org.eclipse.jetty.websocket.javax.tests.CoreServer;
import org.eclipse.jetty.websocket.javax.tests.DataUtils;
import org.eclipse.jetty.websocket.util.TextUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;

View File

@ -29,9 +29,9 @@ import javax.websocket.EndpointConfig;
import org.eclipse.jetty.toolchain.test.Hex;
import org.eclipse.jetty.websocket.javax.client.BasicClientEndpointConfig;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
import org.eclipse.jetty.websocket.javax.common.decoders.AvailableDecoders;
import org.eclipse.jetty.websocket.javax.common.decoders.IntegerDecoder;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

View File

@ -31,9 +31,9 @@ import javax.websocket.EndpointConfig;
import org.eclipse.jetty.toolchain.test.Hex;
import org.eclipse.jetty.websocket.javax.client.BasicClientEndpointConfig;
import org.eclipse.jetty.websocket.javax.common.InvalidWebSocketException;
import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.eclipse.jetty.websocket.javax.common.encoders.IntegerEncoder;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

View File

@ -30,8 +30,8 @@ import java.util.function.Function;
import javax.websocket.Decoder;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.javax.common.CompletableFutureCallback;
import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessageSink;
import org.eclipse.jetty.websocket.javax.tests.FunctionMethod;
import org.eclipse.jetty.websocket.javax.tests.client.AbstractClientSessionTest;
@ -80,14 +80,14 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
return null;
});
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session, decoder, quoteHandle);
DecodedTextStreamMessageSink sink = new DecodedTextStreamMessageSink(session.getCoreSession(), decoder, quoteHandle);
List<CompletableFutureCallback> callbacks = new ArrayList<>();
CompletableFutureCallback finCallback = null;
List<FutureCallback> callbacks = new ArrayList<>();
FutureCallback finCallback = null;
List<Frame> frames = QuotesUtil.loadAsWebSocketFrames("quotes-ben.txt");
for (Frame frame : frames)
{
CompletableFutureCallback callback = new CompletableFutureCallback();
FutureCallback callback = new FutureCallback();
if (frame.isFin())
{
finCallback = callback;
@ -100,7 +100,7 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
finCallback.get(1, TimeUnit.SECONDS); // wait for fin
Quotes quotes = futureQuotes.get(1, TimeUnit.SECONDS);
assertThat("Quotes", quotes, notNullValue());
for (CompletableFutureCallback callback : callbacks)
for (FutureCallback callback : callbacks)
{
assertThat("Callback", callback.isDone(), is(true));
}

View File

@ -29,7 +29,6 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.javax.common.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidCloseIntSocket;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidErrorErrorSocket;
@ -37,6 +36,7 @@ import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidErrorIntSoc
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidOpenCloseReasonSocket;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidOpenIntSocket;
import org.eclipse.jetty.websocket.javax.tests.server.sockets.InvalidOpenSessionIntSocket;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;

View File

@ -56,6 +56,11 @@
<artifactId>websocket-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>

View File

@ -22,11 +22,9 @@ import org.eclipse.jetty.websocket.common.ExtensionConfigParser;
module org.eclipse.jetty.websocket.jetty.common
{
exports org.eclipse.jetty.websocket.common;
exports org.eclipse.jetty.websocket.common.invoke;
exports org.eclipse.jetty.websocket.common.message;
exports org.eclipse.jetty.websocket.common.util;
requires transitive org.eclipse.jetty.websocket.core;
requires transitive org.eclipse.jetty.websocket.util;
requires transitive org.eclipse.jetty.websocket.jetty.api;
provides ExtensionConfig.Parser with ExtensionConfigParser;

View File

@ -1,34 +0,0 @@
//
// ========================================================================
// 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.common;
import java.lang.invoke.MethodHandle;
import java.util.concurrent.Executor;
public abstract class AbstractMessageSink implements MessageSink
{
protected final Executor executor;
protected final MethodHandle methodHandle;
public AbstractMessageSink(Executor executor, MethodHandle methodHandle)
{
this.executor = executor;
this.methodHandle = methodHandle;
}
}

View File

@ -1,48 +0,0 @@
//
// ========================================================================
// 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.common;
import java.util.concurrent.CompletableFuture;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class CompletableFutureCallback extends CompletableFuture<Callback> implements Callback
{
private static final Logger LOG = Log.getLogger(CompletableFutureCallback.class);
@Override
public void failed(Throwable cause)
{
if (LOG.isDebugEnabled())
LOG.debug("failed()", cause);
completeExceptionally(cause);
}
@Override
public void succeeded()
{
if (LOG.isDebugEnabled())
LOG.debug("succeeded()");
complete(this);
}
}

View File

@ -1,51 +0,0 @@
//
// ========================================================================
// 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.common;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
public class FunctionCallException extends WebSocketException
{
public FunctionCallException(String message)
{
super(message);
}
public FunctionCallException(String message, Throwable cause)
{
super(message, cause);
}
public FunctionCallException(Throwable cause)
{
super(cause);
}
public Throwable getInvokedCause()
{
Throwable cause = getCause();
if (cause instanceof InvocationTargetException)
{
return cause.getCause();
}
return cause;
}
}

View File

@ -32,7 +32,6 @@ import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.api.WriteCallback;
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
import org.eclipse.jetty.websocket.core.CloseStatus;
import org.eclipse.jetty.websocket.core.Configuration;
import org.eclipse.jetty.websocket.core.CoreSession;
@ -46,6 +45,9 @@ import org.eclipse.jetty.websocket.core.exception.ProtocolException;
import org.eclipse.jetty.websocket.core.exception.UpgradeException;
import org.eclipse.jetty.websocket.core.exception.WebSocketException;
import org.eclipse.jetty.websocket.core.exception.WebSocketTimeoutException;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
public class JettyWebSocketFrameHandler implements FrameHandler
{
@ -152,14 +154,14 @@ public class JettyWebSocketFrameHandler implements FrameHandler
customizer.customize(coreSession);
session = new WebSocketSession(coreSession, this);
frameHandle = JettyWebSocketFrameHandlerFactory.bindTo(frameHandle, session);
openHandle = JettyWebSocketFrameHandlerFactory.bindTo(openHandle, session);
closeHandle = JettyWebSocketFrameHandlerFactory.bindTo(closeHandle, session);
errorHandle = JettyWebSocketFrameHandlerFactory.bindTo(errorHandle, session);
textHandle = JettyWebSocketFrameHandlerFactory.bindTo(textHandle, session);
binaryHandle = JettyWebSocketFrameHandlerFactory.bindTo(binaryHandle, session);
pingHandle = JettyWebSocketFrameHandlerFactory.bindTo(pingHandle, session);
pongHandle = JettyWebSocketFrameHandlerFactory.bindTo(pongHandle, session);
frameHandle = InvokerUtils.bindTo(frameHandle, session);
openHandle = InvokerUtils.bindTo(openHandle, session);
closeHandle = InvokerUtils.bindTo(closeHandle, session);
errorHandle = InvokerUtils.bindTo(errorHandle, session);
textHandle = InvokerUtils.bindTo(textHandle, session);
binaryHandle = InvokerUtils.bindTo(binaryHandle, session);
pingHandle = InvokerUtils.bindTo(pingHandle, session);
pongHandle = InvokerUtils.bindTo(pongHandle, session);
Executor executor = container.getExecutor();

View File

@ -24,7 +24,7 @@ import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -37,7 +37,6 @@ import java.util.concurrent.Executor;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.Frame;
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketConnectionListener;
import org.eclipse.jetty.websocket.api.WebSocketFrameListener;
@ -50,16 +49,19 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
import org.eclipse.jetty.websocket.common.invoke.InvokerUtils;
import org.eclipse.jetty.websocket.common.message.ByteArrayMessageSink;
import org.eclipse.jetty.websocket.common.message.ByteBufferMessageSink;
import org.eclipse.jetty.websocket.common.message.InputStreamMessageSink;
import org.eclipse.jetty.websocket.common.message.PartialBinaryMessageSink;
import org.eclipse.jetty.websocket.common.message.PartialTextMessageSink;
import org.eclipse.jetty.websocket.common.message.ReaderMessageSink;
import org.eclipse.jetty.websocket.common.message.StringMessageSink;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.InvalidWebSocketException;
import org.eclipse.jetty.websocket.util.InvokerUtils;
import org.eclipse.jetty.websocket.util.ReflectUtils;
import org.eclipse.jetty.websocket.util.messages.ByteArrayMessageSink;
import org.eclipse.jetty.websocket.util.messages.ByteBufferMessageSink;
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialByteBufferMessageSink;
import org.eclipse.jetty.websocket.util.messages.PartialStringMessageSink;
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
/**
* Factory to create {@link JettyWebSocketFrameHandler} instances suitable for
@ -120,16 +122,16 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
{
JettyWebSocketFrameHandlerMetadata metadata = getMetadata(endpointInstance.getClass());
final MethodHandle openHandle = bindTo(metadata.getOpenHandle(), endpointInstance);
final MethodHandle closeHandle = bindTo(metadata.getCloseHandle(), endpointInstance);
final MethodHandle errorHandle = bindTo(metadata.getErrorHandle(), endpointInstance);
final MethodHandle textHandle = bindTo(metadata.getTextHandle(), endpointInstance);
final MethodHandle binaryHandle = bindTo(metadata.getBinaryHandle(), endpointInstance);
final MethodHandle openHandle = InvokerUtils.bindTo(metadata.getOpenHandle(), endpointInstance);
final MethodHandle closeHandle = InvokerUtils.bindTo(metadata.getCloseHandle(), endpointInstance);
final MethodHandle errorHandle = InvokerUtils.bindTo(metadata.getErrorHandle(), endpointInstance);
final MethodHandle textHandle = InvokerUtils.bindTo(metadata.getTextHandle(), endpointInstance);
final MethodHandle binaryHandle = InvokerUtils.bindTo(metadata.getBinaryHandle(), endpointInstance);
final Class<? extends MessageSink> textSinkClass = metadata.getTextSink();
final Class<? extends MessageSink> binarySinkClass = metadata.getBinarySink();
final MethodHandle frameHandle = bindTo(metadata.getFrameHandle(), endpointInstance);
final MethodHandle pingHandle = bindTo(metadata.getPingHandle(), endpointInstance);
final MethodHandle pongHandle = bindTo(metadata.getPongHandle(), endpointInstance);
final MethodHandle frameHandle = InvokerUtils.bindTo(metadata.getFrameHandle(), endpointInstance);
final MethodHandle pingHandle = InvokerUtils.bindTo(metadata.getPingHandle(), endpointInstance);
final MethodHandle pongHandle = InvokerUtils.bindTo(metadata.getPongHandle(), endpointInstance);
BatchMode batchMode = metadata.getBatchMode();
JettyWebSocketFrameHandler frameHandler = new JettyWebSocketFrameHandler(
@ -154,46 +156,26 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
try
{
try
{
Constructor sinkConstructor = sinkClass.getConstructor(Executor.class, MethodHandle.class, Session.class);
MessageSink messageSink = (MessageSink)sinkConstructor.newInstance(executor, msgHandle, session);
return messageSink;
}
catch (NoSuchMethodException e)
{
try
{
Constructor sinkConstructor = sinkClass.getConstructor(Executor.class, MethodHandle.class);
MessageSink messageSink = (MessageSink)sinkConstructor.newInstance(executor, msgHandle);
return messageSink;
}
catch (NoSuchMethodException e2)
{
e.addSuppressed(e2);
throw new RuntimeException("Missing expected MessageSink constructor found at: " + sinkClass.getName(), e);
}
}
MethodHandle ctorHandle = MethodHandles.lookup().findConstructor(sinkClass,
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class));
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgHandle);
}
catch (NoSuchMethodException e)
{
throw new RuntimeException("Missing expected MessageSink constructor found at: " + sinkClass.getName(), e);
}
catch (IllegalAccessException | InstantiationException | InvocationTargetException e)
{
throw new RuntimeException("Unable to create MessageSink: " + sinkClass.getName(), e);
}
}
public static MethodHandle bindTo(MethodHandle methodHandle, Object... objs)
{
if (methodHandle == null)
return null;
MethodHandle ret = methodHandle;
for (Object obj : objs)
catch (RuntimeException e)
{
if (ret.type().parameterType(0).isAssignableFrom(obj.getClass()))
{
ret = ret.bindTo(obj);
}
throw e;
}
catch (Throwable t)
{
throw new RuntimeException(t);
}
return ret;
}
private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method)
@ -211,8 +193,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
private JettyWebSocketFrameHandlerMetadata createListenerMetadata(Class<?> endpointClass)
{
JettyWebSocketFrameHandlerMetadata metadata = new JettyWebSocketFrameHandlerMetadata();
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass);
Method openMethod = ReflectUtils.findMethod(endpointClass, "onWebSocketConnect", Session.class);
MethodHandle open = toMethodHandle(lookup, openMethod);
@ -255,11 +236,11 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
{
Method textMethod = ReflectUtils.findMethod(endpointClass, "onWebSocketPartialText", String.class, boolean.class);
MethodHandle text = toMethodHandle(lookup, textMethod);
metadata.setTextHandler(PartialTextMessageSink.class, text, textMethod);
metadata.setTextHandler(PartialStringMessageSink.class, text, textMethod);
Method binaryMethod = ReflectUtils.findMethod(endpointClass, "onWebSocketPartialBinary", ByteBuffer.class, boolean.class);
MethodHandle binary = toMethodHandle(lookup, binaryMethod);
metadata.setBinaryHandle(PartialBinaryMessageSink.class, binary, binaryMethod);
metadata.setBinaryHandle(PartialByteBufferMessageSink.class, binary, binaryMethod);
}
// Frame Listener
@ -291,6 +272,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
metadata.setIdleTimeout(Duration.ofMillis(max));
metadata.setBatchMode(anno.batchMode());
MethodHandles.Lookup lookup = getMethodHandleLookup(endpointClass);
Method onmethod;
// OnWebSocketConnect [0..1]
@ -299,7 +281,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
{
assertSignatureValid(endpointClass, onmethod, OnWebSocketConnect.class);
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class).required();
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(endpointClass, onmethod, SESSION);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, endpointClass, onmethod, SESSION);
metadata.setOpenHandler(methodHandle, onmethod);
}
@ -311,7 +293,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
final InvokerUtils.Arg STATUS_CODE = new InvokerUtils.Arg(int.class);
final InvokerUtils.Arg REASON = new InvokerUtils.Arg(String.class);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(endpointClass, onmethod, SESSION, STATUS_CODE, REASON);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, endpointClass, onmethod, SESSION, STATUS_CODE, REASON);
// TODO: need mutation of args? ...
// Session + CloseInfo ->
// setOnClose((closeInfo) ->{
@ -328,7 +310,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
assertSignatureValid(endpointClass, onmethod, OnWebSocketError.class);
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
final InvokerUtils.Arg CAUSE = new InvokerUtils.Arg(Throwable.class).required();
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(endpointClass, onmethod, SESSION, CAUSE);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, endpointClass, onmethod, SESSION, CAUSE);
metadata.setErrorHandler(methodHandle, onmethod);
}
@ -339,7 +321,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
assertSignatureValid(endpointClass, onmethod, OnWebSocketFrame.class);
final InvokerUtils.Arg SESSION = new InvokerUtils.Arg(Session.class);
final InvokerUtils.Arg FRAME = new InvokerUtils.Arg(Frame.class).required();
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(endpointClass, onmethod, SESSION, FRAME);
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, endpointClass, onmethod, SESSION, FRAME);
metadata.setFrameHandler(methodHandle, onmethod);
}
@ -381,7 +363,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
{
assertSignatureValid(endpointClass, onMsg, OnWebSocketMessage.class);
MethodHandle methodHandle = InvokerUtils.optionalMutatedInvoker(endpointClass, onMsg, InvokerUtils.PARAM_IDENTITY, textCallingArgs);
MethodHandle methodHandle = InvokerUtils.optionalMutatedInvoker(lookup, endpointClass, onMsg, textCallingArgs);
if (methodHandle != null)
{
// Normal Text Message
@ -390,7 +372,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
continue onmessageloop;
}
methodHandle = InvokerUtils.optionalMutatedInvoker(endpointClass, onMsg, InvokerUtils.PARAM_IDENTITY, binaryBufferCallingArgs);
methodHandle = InvokerUtils.optionalMutatedInvoker(lookup, endpointClass, onMsg, binaryBufferCallingArgs);
if (methodHandle != null)
{
// ByteBuffer Binary Message
@ -399,7 +381,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
continue onmessageloop;
}
methodHandle = InvokerUtils.optionalMutatedInvoker(endpointClass, onMsg, InvokerUtils.PARAM_IDENTITY, binaryArrayCallingArgs);
methodHandle = InvokerUtils.optionalMutatedInvoker(lookup, endpointClass, onMsg, binaryArrayCallingArgs);
if (methodHandle != null)
{
// byte[] Binary Message
@ -408,7 +390,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
continue onmessageloop;
}
methodHandle = InvokerUtils.optionalMutatedInvoker(endpointClass, onMsg, InvokerUtils.PARAM_IDENTITY, inputStreamCallingArgs);
methodHandle = InvokerUtils.optionalMutatedInvoker(lookup, endpointClass, onMsg, inputStreamCallingArgs);
if (methodHandle != null)
{
// InputStream Binary Message
@ -417,7 +399,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
continue onmessageloop;
}
methodHandle = InvokerUtils.optionalMutatedInvoker(endpointClass, onMsg, InvokerUtils.PARAM_IDENTITY, readerCallingArgs);
methodHandle = InvokerUtils.optionalMutatedInvoker(lookup, endpointClass, onMsg, readerCallingArgs);
if (methodHandle != null)
{
// Reader Text Message
@ -473,6 +455,20 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
throw new InvalidSignatureException(err.toString());
}
private MethodHandles.Lookup getMethodHandleLookup(Class<?> endpointClass) throws InvalidWebSocketException
{
MethodHandles.Lookup lookup;
try
{
lookup = MethodHandles.privateLookupIn(endpointClass, MethodHandles.lookup());
}
catch (IllegalAccessException e)
{
throw new InvalidWebSocketException("Unable to obtain MethodHandle lookup for " + endpointClass, e);
}
return lookup;
}
@Override
public void dump(Appendable out, String indent) throws IOException
{

View File

@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandle;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
import org.eclipse.jetty.websocket.core.Configuration;
import org.eclipse.jetty.websocket.util.messages.MessageSink;
public class JettyWebSocketFrameHandlerMetadata extends Configuration.ConfigurationCustomizer
{

View File

@ -1,72 +0,0 @@
//
// ========================================================================
// 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.common.invoke;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
@SuppressWarnings("serial")
public class InvalidSignatureException extends InvalidWebSocketException
{
public static InvalidSignatureException build(Class<?> pojo, Class<? extends Annotation> methodAnnotationClass, Method method)
{
StringBuilder err = new StringBuilder();
err.append("Invalid ");
if (methodAnnotationClass != null)
{
err.append("@");
err.append(methodAnnotationClass.getSimpleName());
err.append(' ');
}
if (pojo != null)
{
ReflectUtils.append(err, method);
}
else
{
ReflectUtils.append(err, pojo, method);
}
return new InvalidSignatureException(err.toString());
}
public static InvalidSignatureException build(MethodType expectedType, MethodType actualType)
{
StringBuilder err = new StringBuilder();
err.append("Invalid MethodHandle ");
ReflectUtils.append(err, actualType);
err.append(" - expected ");
ReflectUtils.append(err, expectedType);
return new InvalidSignatureException(err.toString());
}
public InvalidSignatureException(String message)
{
super(message);
}
public InvalidSignatureException(String message, Throwable cause)
{
super(message, cause);
}
}

View File

@ -1,369 +0,0 @@
//
// ========================================================================
// 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.common.invoke;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jetty.websocket.common.util.ReflectUtils;
public class InvokerUtils
{
public static class Arg
{
private final Class<?> type;
private boolean required = false;
private String name;
public Arg(Class<?> type)
{
this.type = type;
}
public Arg(Class<?> type, String name)
{
this.type = type;
this.name = name;
}
public String getName()
{
return name;
}
public boolean matches(Arg other)
{
// If tags exist
if (this.name != null)
{
// They have to match
return (this.name.equals(other.name));
}
// Lastly, if types match, use em
return (this.type.isAssignableFrom(other.type));
}
public Arg required()
{
this.required = true;
return this;
}
public Class<?> getType()
{
return type;
}
public boolean isRequired()
{
return required;
}
}
public interface ParamIdentifier
{
Arg getParamArg(Method method, Class<?> paramType, int idx);
}
private static class ParamIdentity implements ParamIdentifier
{
@Override
public Arg getParamArg(Method method, Class<?> paramType, int idx)
{
return new Arg(paramType);
}
}
public static final ParamIdentifier PARAM_IDENTITY = new ParamIdentity();
/**
* Build a MethodHandle that can call the method with the calling args provided.
* <p>
* Might need to drop calling args and/or reorder the calling args to fit
* the actual method being called.
* </p>
*
* @param targetClass the target class for invocations of the resulting MethodHandle (also known as parameter 0)
* @param method the method to invoke
* @param callingArgs the calling arguments
* @return the MethodHandle for this set of CallingArgs
*/
public static MethodHandle mutatedInvoker(Class<?> targetClass, Method method, Arg... callingArgs)
{
return mutatedInvoker(targetClass, method, PARAM_IDENTITY, callingArgs);
}
/**
* Create a MethodHandle that performs the following layers
* <ol>
* <li>{@link MethodHandles#permuteArguments(MethodHandle, MethodType, int...)} - moving calling Args around
* to fit actual actual method parameter arguments (in proper order), with remaining (unused) calling args afterwords</li>
* <li>{@link MethodHandles#dropArguments(MethodHandle, int, Class[])} - to drop the unused calling args</li>
* <li>{@link MethodHandle#invoke(Object...)} - to call the specific method</li>
* </ol>
*
* @param targetClass the target class for invocations of the resulting MethodHandle (also known as parameter 0)
* @param method the method to invoke
* @param paramIdentifier the mechanism to identify parameters in method
* @param callingArgs the calling arguments
* @return the MethodHandle for this set of CallingArgs
* @throws RuntimeException when unable to fit Calling Args to Parameter Types
*/
public static MethodHandle mutatedInvoker(Class<?> targetClass, Method method, ParamIdentifier paramIdentifier, Arg... callingArgs)
{
return mutatedInvoker(targetClass, true, method, paramIdentifier, callingArgs);
}
private static MethodHandle mutatedInvoker(Class<?> targetClass, boolean throwOnFailure, Method method, ParamIdentifier paramIdentifier, Arg... callingArgs)
{
Class<?>[] parameterTypes = method.getParameterTypes();
// Build up Arg list representing the MethodHandle parameters
// ParamIdentifier is used to find named parameters (like javax.websocket's @PathParam declaration)
boolean hasNamedParamArgs = false;
Arg[] parameterArgs = new Arg[parameterTypes.length + 1];
parameterArgs[0] = new Arg(targetClass); // first type is always the calling object instance type
for (int i = 0; i < parameterTypes.length; i++)
{
Arg arg = paramIdentifier.getParamArg(method, parameterTypes[i], i);
if (arg.name != null)
{
hasNamedParamArgs = true;
}
parameterArgs[i + 1] = arg;
}
// Parameter to Calling Argument mapping.
// The size of this array must be the the same as the parameterArgs array (or bigger)
if (callingArgs.length < parameterTypes.length)
{
if (!throwOnFailure)
{
return null;
}
StringBuilder err = new StringBuilder();
err.append("Target method ");
ReflectUtils.append(err, targetClass, method);
err.append(" contains too many parameters and cannot be mapped to expected callable args ");
appendTypeList(err, callingArgs);
throw new InvalidSignatureException(err.toString());
}
// Establish MethodType for supplied calling args
boolean hasNamedCallingArgs = false;
List<Class<?>> cTypes = new ArrayList<>();
cTypes.add(targetClass); // targetClass always at index 0
for (int i = 0; i < callingArgs.length; i++)
{
Arg arg = callingArgs[i];
if (arg.name != null)
{
hasNamedCallingArgs = true;
}
cTypes.add(arg.getType());
}
MethodType callingType = MethodType.methodType(method.getReturnType(), cTypes);
// Create low level MethodHandle
MethodHandles.Lookup lookup = MethodHandles.lookup();
try
{
// Low level invoker.
// We intentionally do not use lookup#unreflect() as that will incorrectly preserve
// the calling 'refc' type of where the method is declared, not the targetClass.
// That behavior of #unreflect() results in a MethodType referring to the
// base/abstract/interface where the method is declared, and not the targetClass
MethodType rawType = MethodType.methodType(method.getReturnType(), method.getParameterTypes());
MethodHandle methodHandle = lookup.findVirtual(targetClass, method.getName(), rawType);
// If callingType and rawType are the same (and there's no named args),
// then there's no need to reorder / permute / drop args
if (!hasNamedCallingArgs && !hasNamedParamArgs && rawType.equals(callingType))
{
return methodHandle;
}
// If we reached this point, then we know that the callingType and rawType don't
// match, so we have to drop and/or permute(reorder) the arguments
// Mapping will be same size as callingType (to compensate for targetClass at index 0)
int[] reorderMap = new int[callingType.parameterCount()];
Arrays.fill(reorderMap, -1);
reorderMap[0] = 0; // always references targetClass
// To track which callingArgs have been used.
// If a callingArg is used, it is used only once.
boolean[] usedCallingArgs = new boolean[callingArgs.length];
Arrays.fill(usedCallingArgs, false);
// Iterate through each parameterArg and attempt to find an associated callingArg
for (int pi = 1; pi < parameterArgs.length; pi++)
{
int ref = -1;
// Find a reference to argument in callArgs
for (int ci = 0; ci < callingArgs.length; ci++)
{
if (!usedCallingArgs[ci] && parameterArgs[pi].matches(callingArgs[ci]))
{
ref = ci + 1; // add 1 to compensate for parameter 0
usedCallingArgs[ci] = true;
break;
}
}
// Didn't find an unused callingArg that fits this parameterArg
if (ref < 0)
{
if (!throwOnFailure)
{
return null;
}
StringBuilder err = new StringBuilder();
err.append("Invalid mapping of type [");
err.append(parameterArgs[pi].getType());
err.append("] in method ");
ReflectUtils.append(err, method);
err.append(" to calling args ");
appendTypeList(err, callingArgs);
throw new InvalidSignatureException(err.toString());
}
reorderMap[pi] = ref;
}
// Remaining unused callingArgs are to be placed at end of specified reorderMap
for (int ri = parameterArgs.length; ri <= reorderMap.length; ri++)
{
for (int uci = 0; uci < usedCallingArgs.length; uci++)
{
if (usedCallingArgs[uci] == false)
{
if (callingArgs[uci].required)
{
if (!throwOnFailure)
{
return null;
}
StringBuilder err = new StringBuilder();
err.append("Missing required argument [");
err.append(callingArgs[uci].getType().getName());
err.append("] in method ");
ReflectUtils.append(err, method);
throw new InvalidSignatureException(err.toString());
}
reorderMap[ri] = uci + 1; // compensate for parameter 0
ri++;
}
}
}
// Drop excess (not mapped to a method parameter) calling args
int idxDrop = parameterArgs.length;
int dropLength = reorderMap.length - idxDrop;
if (dropLength > 0)
{
List<Class<?>> dropTypes = new ArrayList<>();
for (int i = 0; i < dropLength; i++)
{
int callingTypeIdx = reorderMap[idxDrop + i];
dropTypes.add(callingType.parameterType(callingTypeIdx));
}
methodHandle = MethodHandles.dropArguments(methodHandle, idxDrop, dropTypes);
}
// Reorder calling args to parameter args
methodHandle = MethodHandles.permuteArguments(methodHandle, callingType, reorderMap);
// Return method handle
return methodHandle;
}
catch (IllegalAccessException | NoSuchMethodException e)
{
// TODO: throw Invalid Invoker Exception
if (!throwOnFailure)
{
return null;
}
throw new InvalidSignatureException("Unable to obtain MethodHandle for " + method, e);
}
}
/**
* Create an optional MethodHandle that performs the following layers.
* <ol>
* <li>{@link MethodHandles#permuteArguments(MethodHandle, MethodType, int...)} - moving calling Args around
* to fit actual actual method parameter arguments (in proper order), with remaining (unused) calling args afterwords</li>
* <li>{@link MethodHandles#dropArguments(MethodHandle, int, Class[])} - to drop the unused calling args</li>
* <li>{@link MethodHandle#invoke(Object...)} - to call the specific method</li>
* </ol>
*
* @param targetClass the target class for invocations of the resulting MethodHandle (also known as parameter 0)
* @param method the method to invoke
* @param paramIdentifier the mechanism to identify parameters in method
* @param callingArgs the calling arguments
* @return the MethodHandle for this set of CallingArgs, or null if not possible to create MethodHandle with CallingArgs to provided method
*/
public static MethodHandle optionalMutatedInvoker(Class<?> targetClass, Method method, ParamIdentifier paramIdentifier, Arg... callingArgs)
{
return mutatedInvoker(targetClass, false, method, paramIdentifier, callingArgs);
}
private static void appendTypeList(StringBuilder str, Arg[] args)
{
str.append("(");
boolean comma = false;
for (Arg arg : args)
{
if (comma)
str.append(", ");
str.append(arg.getType().getName());
comma = true;
}
str.append(")");
}
private static void appendTypeList(StringBuilder str, Class<?>[] types)
{
str.append("(");
boolean comma = false;
for (Class<?> type : types)
{
if (comma)
str.append(", ");
str.append(type.getName());
comma = true;
}
str.append(")");
}
}

View File

@ -1,105 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.io.ByteArrayOutputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.common.AbstractMessageSink;
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
public class ByteArrayMessageSink extends AbstractMessageSink
{
private static final byte[] EMPTY_BUFFER = new byte[0];
private static final int BUFFER_SIZE = 65535;
private final Session session;
private ByteArrayOutputStream out;
private int size;
public ByteArrayMessageSink(Executor executor, MethodHandle methodHandle, Session session)
{
super(executor, methodHandle);
this.session = session;
Objects.requireNonNull(methodHandle, "MethodHandle");
// byte[] buf, int offset, int length
MethodType onMessageType = MethodType.methodType(Void.TYPE, byte[].class, int.class, int.class);
if (methodHandle.type() != onMessageType)
{
throw InvalidSignatureException.build(onMessageType, methodHandle.type());
}
}
@SuppressWarnings("Duplicates")
@Override
public void accept(Frame frame, Callback callback)
{
try
{
if (frame.hasPayload())
{
ByteBuffer payload = frame.getPayload();
size = size + payload.remaining();
long maxMessageSize = session.getMaxBinaryMessageSize();
if (maxMessageSize > 0 && size > maxMessageSize)
throw new MessageTooLargeException("Message size [" + size + "] exceeds maximum size [" + maxMessageSize + "]");
if (out == null)
out = new ByteArrayOutputStream(BUFFER_SIZE);
BufferUtil.writeTo(payload, out);
}
if (frame.isFin())
{
if (out != null)
{
byte[] buf = out.toByteArray();
methodHandle.invoke(buf, 0, buf.length);
}
else
methodHandle.invoke(EMPTY_BUFFER, 0, 0);
}
callback.succeeded();
}
catch (Throwable t)
{
callback.failed(t);
}
finally
{
if (frame.isFin())
{
// reset
out = null;
size = 0;
}
}
}
}

View File

@ -1,42 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
public class CallbackBuffer
{
public ByteBuffer buffer;
public Callback callback;
public CallbackBuffer(Callback callback, ByteBuffer buffer)
{
this.callback = callback;
this.buffer = buffer;
}
@Override
public String toString()
{
return String.format("CallbackBuffer[%s,%s]", BufferUtil.toDetailString(buffer), callback.getClass().getSimpleName());
}
}

View File

@ -1,176 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.lang.invoke.MethodHandle;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.common.AbstractMessageSink;
import org.eclipse.jetty.websocket.common.MessageSink;
import org.eclipse.jetty.websocket.core.Frame;
/**
* Centralized logic for Dispatched Message Handling.
* <p>
* A Dispatched MessageSink can consist of 1 or more {@link #accept(Frame, Callback)} calls.
* <p>
* The first {@link #accept(Frame, Callback)} in a message will trigger a dispatch to the
* function specified in the constructor.
* <p>
* The completion of the dispatched function call is the sign that the next message is suitable
* for processing from the network. (The connection fillAndParse should remain idle for the
* NEXT message until such time as the dispatched function call has completed)
* </p>
* <p>
* There are a few use cases we need to handle.
* </p>
* <p>
* <em>1. Normal Processing</em>
* </p>
* <pre>
* Connection Thread | DispatchedMessageSink | Thread 2
* TEXT accept()
* - dispatch - function.read(stream)
* CONT accept() stream.read()
* CONT accept() stream.read()
* CONT=fin accept() stream.read()
* EOF stream.read EOF
* IDLE
* exit method
* RESUME(NEXT MSG)
* </pre>
* <p>
* <em>2. Early Exit (with no activity)</em>
* </p>
* <pre>
* Connection Thread | DispatchedMessageSink | Thread 2
* TEXT accept()
* - dispatch - function.read(stream)
* CONT accept() exit method (normal return)
* IDLE
* TIMEOUT
* </pre>
* <p>
* <em>3. Early Exit (due to exception)</em>
* </p>
* <pre>
* Connection Thread | DispatchedMessageSink | Thread 2
* TEXT accept()
* - dispatch - function.read(stream)
* CONT accept() exit method (throwable)
* callback.fail()
* endpoint.onError()
* close(error)
* </pre>
* <p>
* <em>4. Early Exit (with Custom Threading)</em>
* </p>
* <pre>
* Connection Thread | DispatchedMessageSink | Thread 2 | Thread 3
* TEXT accept()
* - dispatch - function.read(stream)
* thread.new(stream) stream.read()
* exit method
* CONT accept() stream.read()
* CONT accept() stream.read()
* CONT=fin accept() stream.read()
* EOF stream.read EOF
* RESUME(NEXT MSG)
* </pre>
*
* @param <T> the type of object to give to user function
* @param <R> the type of object that user function will return
*/
public abstract class DispatchedMessageSink<T, R> extends AbstractMessageSink
{
private CompletableFuture<Void> dispatchComplete;
private MessageSink typeSink;
public DispatchedMessageSink(Executor executor, MethodHandle methodHandle)
{
super(executor, methodHandle);
Objects.requireNonNull(this.executor, "Executor");
}
public abstract MessageSink newSink(Frame frame);
public void accept(Frame frame, final Callback callback)
{
if (typeSink == null)
{
typeSink = newSink(frame);
// Dispatch to end user function (will likely start with blocking for data/accept)
dispatchComplete = new CompletableFuture<>();
executor.execute(() ->
{
final T dispatchedType = (T)typeSink;
try
{
methodHandle.invoke(dispatchedType);
dispatchComplete.complete(null);
}
catch (Throwable throwable)
{
dispatchComplete.completeExceptionally(throwable);
}
});
}
final Callback frameCallback;
if (frame.isFin())
{
CompletableFuture<Void> finComplete = new CompletableFuture<>();
frameCallback = new Callback()
{
@Override
public void failed(Throwable cause)
{
finComplete.completeExceptionally(cause);
}
@Override
public void succeeded()
{
finComplete.complete(null);
}
};
CompletableFuture.allOf(dispatchComplete, finComplete).whenComplete(
(aVoid, throwable) ->
{
typeSink = null;
dispatchComplete = null;
if (throwable != null)
callback.failed(throwable);
else
callback.succeeded();
});
}
else
{
// Non-fin-frame
frameCallback = callback;
}
typeSink.accept(frame, frameCallback);
}
}

View File

@ -1,40 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.io.InputStream;
import java.lang.invoke.MethodHandle;
import java.util.concurrent.Executor;
import org.eclipse.jetty.websocket.common.MessageSink;
import org.eclipse.jetty.websocket.core.Frame;
public class InputStreamMessageSink extends DispatchedMessageSink<InputStream, Void>
{
public InputStreamMessageSink(Executor executor, MethodHandle methodHandle)
{
super(executor, methodHandle);
}
@Override
public MessageSink newSink(Frame frame)
{
return new MessageInputStream();
}
}

View File

@ -1,227 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.MessageSink;
import org.eclipse.jetty.websocket.core.Frame;
/**
* Support class for reading a WebSocket BINARY message via a InputStream.
* <p>
* An InputStream that can access a queue of ByteBuffer payloads, along with expected InputStream blocking behavior.
* </p>
*/
public class MessageInputStream extends InputStream implements MessageSink
{
private static final Logger LOG = Log.getLogger(MessageInputStream.class);
private static final CallbackBuffer EOF = new CallbackBuffer(Callback.NOOP, ByteBuffer.allocate(0).asReadOnlyBuffer());
private final Deque<CallbackBuffer> buffers = new ArrayDeque<>(2);
private final AtomicBoolean closed = new AtomicBoolean(false);
private CallbackBuffer activeFrame;
@Override
public void accept(Frame frame, Callback callback)
{
if (LOG.isDebugEnabled())
LOG.debug("accepting {}", frame);
// If closed, we should just toss incoming payloads into the bit bucket.
if (closed.get())
{
callback.failed(new IOException("Already Closed"));
return;
}
if (!frame.hasPayload() && !frame.isFin())
{
callback.succeeded();
return;
}
synchronized (buffers)
{
boolean notify = false;
if (frame.hasPayload())
{
buffers.offer(new CallbackBuffer(callback, frame.getPayload()));
notify = true;
}
else
{
// We cannot wake up blocking read for a zero length frame.
callback.succeeded();
}
if (frame.isFin())
{
buffers.offer(EOF);
notify = true;
}
if (notify)
{
// notify other thread
buffers.notify();
}
}
}
@Override
public void close() throws IOException
{
if (LOG.isDebugEnabled())
LOG.debug("close()");
if (closed.compareAndSet(false, true))
{
synchronized (buffers)
{
buffers.offer(EOF);
buffers.notify();
}
}
super.close();
}
public CallbackBuffer getActiveFrame() throws InterruptedIOException
{
if (activeFrame == null)
{
// sync and poll queue
CallbackBuffer result;
synchronized (buffers)
{
try
{
while ((result = buffers.poll()) == null)
{
// TODO: handle read timeout here?
buffers.wait();
}
}
catch (InterruptedException e)
{
shutdown();
throw new InterruptedIOException();
}
}
activeFrame = result;
}
return activeFrame;
}
private void shutdown()
{
if (LOG.isDebugEnabled())
LOG.debug("shutdown()");
synchronized (buffers)
{
closed.set(true);
Throwable cause = new IOException("Shutdown");
for (CallbackBuffer buffer : buffers)
{
buffer.callback.failed(cause);
}
// Removed buffers that may have remained in the queue.
buffers.clear();
}
}
@Override
public void mark(int readlimit)
{
// Not supported.
}
@Override
public boolean markSupported()
{
return false;
}
@Override
public int read() throws IOException
{
byte[] buf = new byte[1];
while (true)
{
int len = read(buf, 0, 1);
if (len < 0) // EOF
return -1;
if (len > 0) // did read something
return buf[0];
// reading nothing (len == 0) tries again
}
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException
{
if (closed.get())
{
if (LOG.isDebugEnabled())
LOG.debug("Stream closed");
return -1;
}
CallbackBuffer result = getActiveFrame();
if (LOG.isDebugEnabled())
LOG.debug("result = {}", result);
if (result == EOF)
{
if (LOG.isDebugEnabled())
LOG.debug("Read EOF");
shutdown();
return -1;
}
// We have content
int fillLen = Math.min(result.buffer.remaining(), len);
result.buffer.get(b, off, fillLen);
if (!result.buffer.hasRemaining())
{
activeFrame = null;
result.callback.succeeded();
}
// return number of bytes actually copied into buffer
return fillLen;
}
@Override
public void reset() throws IOException
{
throw new IOException("reset() not supported");
}
}

View File

@ -1,218 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
/**
* Support for writing a single WebSocket BINARY message via a {@link OutputStream}
*/
public class MessageOutputStream extends OutputStream
{
private static final Logger LOG = Log.getLogger(MessageOutputStream.class);
private final CoreSession coreSession;
private final ByteBufferPool bufferPool;
private long frameCount;
private long bytesSent;
private Frame frame;
private ByteBuffer buffer; // Kept in fill mode
private Callback callback;
private boolean closed;
public MessageOutputStream(CoreSession coreSession, int bufferSize, ByteBufferPool bufferPool)
{
this.coreSession = coreSession;
this.bufferPool = bufferPool;
this.buffer = bufferPool.acquire(bufferSize, true);
BufferUtil.flipToFill(buffer);
this.frame = new Frame(OpCode.BINARY);
}
@Override
public void write(byte[] bytes, int off, int len) throws IOException
{
try
{
send(bytes, off, len);
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
@Override
public void write(int b) throws IOException
{
try
{
send(new byte[]{(byte)b}, 0, 1);
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
@Override
public void flush() throws IOException
{
try
{
flush(false);
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
private void flush(boolean fin) throws IOException
{
synchronized (this)
{
if (closed)
throw new IOException("Stream is closed");
closed = fin;
BufferUtil.flipToFlush(buffer, 0);
frame.setPayload(buffer);
frame.setFin(fin);
try
{
FutureCallback b = new FutureCallback();
coreSession.sendFrame(frame, b, false);
b.block();
assert buffer.remaining() == 0;
}
finally
{
BufferUtil.clearToFill(buffer);
}
++frameCount;
// Any flush after the first will be a CONTINUATION frame.
frame = new Frame(OpCode.CONTINUATION);
}
}
private void send(byte[] bytes, final int offset, final int length) throws IOException
{
synchronized (this)
{
if (closed)
throw new IOException("Stream is closed");
int remaining = length;
int off = offset;
int space = buffer.remaining();
while (remaining > 0)
{
// There may be no space available, we want
// to handle correctly when space == 0.
int size = Math.min(space, remaining);
buffer.put(bytes, off, size);
off += size;
remaining -= size;
space = buffer.remaining();
if (space == 0)
{
flush(false);
space = buffer.remaining();
}
}
bytesSent += length;
}
}
@Override
public void close() throws IOException
{
try
{
flush(true);
bufferPool.release(buffer);
if (LOG.isDebugEnabled())
LOG.debug("Stream closed, {} frames ({} bytes) sent", frameCount, bytesSent);
// Notify without holding locks.
notifySuccess();
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
public void setCallback(Callback callback)
{
synchronized (this)
{
this.callback = callback;
}
}
private void notifySuccess()
{
Callback callback;
synchronized (this)
{
callback = this.callback;
}
if (callback != null)
{
callback.succeeded();
}
}
private void notifyFailure(Throwable failure)
{
Callback callback;
synchronized (this)
{
callback = this.callback;
}
if (callback != null)
{
callback.failed(failure);
}
}
}

View File

@ -1,222 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.io.IOException;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.FutureCallback;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Support for writing a single WebSocket TEXT message via a {@link Writer}
* <p>
* Note: Per WebSocket spec, all WebSocket TEXT messages must be encoded in UTF-8
*/
public class MessageWriter extends Writer
{
private static final Logger LOG = Log.getLogger(MessageWriter.class);
private final CharsetEncoder utf8Encoder = UTF_8.newEncoder()
.onUnmappableCharacter(CodingErrorAction.REPORT)
.onMalformedInput(CodingErrorAction.REPORT);
private final CoreSession coreSession;
private long frameCount;
private Frame frame;
private CharBuffer buffer;
private Callback callback;
private boolean closed;
public MessageWriter(CoreSession coreSession, int bufferSize)
{
this.coreSession = coreSession;
this.buffer = CharBuffer.allocate(bufferSize);
this.frame = new Frame(OpCode.TEXT);
}
@Override
public void write(char[] chars, int off, int len) throws IOException
{
try
{
send(chars, off, len);
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
@Override
public void write(int c) throws IOException
{
try
{
send(new char[]{(char)c}, 0, 1);
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
@Override
public void flush() throws IOException
{
try
{
flush(false);
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
private void flush(boolean fin) throws IOException
{
synchronized (this)
{
if (closed)
throw new IOException("Stream is closed");
closed = fin;
buffer.flip();
ByteBuffer payload = utf8Encoder.encode(buffer);
buffer.flip();
if (LOG.isDebugEnabled())
LOG.debug("flush({}): {}", fin, BufferUtil.toDetailString(payload));
frame.setPayload(payload);
frame.setFin(fin);
FutureCallback b = new FutureCallback();
coreSession.sendFrame(frame, b, false);
b.block();
++frameCount;
// Any flush after the first will be a CONTINUATION frame.
frame = new Frame(OpCode.CONTINUATION);
}
}
private void send(char[] chars, int offset, int length) throws IOException
{
synchronized (this)
{
if (closed)
throw new IOException("Stream is closed");
CharBuffer source = CharBuffer.wrap(chars, offset, length);
int remaining = length;
while (remaining > 0)
{
int read = source.read(buffer);
if (read == -1)
{
return;
}
remaining -= read;
if (remaining > 0)
{
// If we could not write everything, it means
// that the buffer was full, so flush it.
flush(false);
}
}
}
}
@Override
public void close() throws IOException
{
try
{
flush(true);
if (LOG.isDebugEnabled())
LOG.debug("Stream closed, {} frames sent", frameCount);
// Notify without holding locks.
notifySuccess();
}
catch (Throwable x)
{
// Notify without holding locks.
notifyFailure(x);
throw x;
}
}
public void setCallback(Callback callback)
{
synchronized (this)
{
this.callback = callback;
}
}
private void notifySuccess()
{
Callback callback;
synchronized (this)
{
callback = this.callback;
}
if (callback != null)
{
callback.succeeded();
}
}
private void notifyFailure(Throwable failure)
{
Callback callback;
synchronized (this)
{
callback = this.callback;
}
if (callback != null)
{
callback.failed(failure);
}
}
}

View File

@ -1,48 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.lang.invoke.MethodHandle;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.common.AbstractMessageSink;
import org.eclipse.jetty.websocket.core.Frame;
public class PartialBinaryMessageSink extends AbstractMessageSink
{
public PartialBinaryMessageSink(Executor executor, MethodHandle methodHandle)
{
super(executor, methodHandle);
}
@Override
public void accept(Frame frame, Callback callback)
{
try
{
methodHandle.invoke(frame.getPayload(), frame.isFin());
callback.succeeded();
}
catch (Throwable t)
{
callback.failed(t);
}
}
}

View File

@ -1,59 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.lang.invoke.MethodHandle;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.websocket.common.AbstractMessageSink;
import org.eclipse.jetty.websocket.core.Frame;
public class PartialTextMessageSink extends AbstractMessageSink
{
private final Utf8StringBuilder utf8Partial;
public PartialTextMessageSink(Executor executor, MethodHandle methodHandle)
{
super(executor, methodHandle);
this.utf8Partial = new Utf8StringBuilder();
}
@Override
public void accept(Frame frame, Callback callback)
{
utf8Partial.append(frame.getPayload());
String partialText = utf8Partial.takePartialString();
try
{
methodHandle.invoke(partialText, frame.isFin());
callback.succeeded();
}
catch (Throwable t)
{
callback.failed(t);
}
finally
{
if (frame.isFin())
utf8Partial.reset();
}
}
}

View File

@ -1,39 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.io.Reader;
import java.lang.invoke.MethodHandle;
import java.util.concurrent.Executor;
import org.eclipse.jetty.websocket.core.Frame;
public class ReaderMessageSink extends DispatchedMessageSink<Reader, Void>
{
public ReaderMessageSink(Executor executor, MethodHandle methodHandle)
{
super(executor, methodHandle);
}
@Override
public MessageReader newSink(Frame frame)
{
return new MessageReader(new MessageInputStream());
}
}

View File

@ -1,105 +0,0 @@
//
// ========================================================================
// 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.common.message;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.Executor;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.common.AbstractMessageSink;
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
public class StringMessageSink extends AbstractMessageSink
{
private static final Logger LOG = Log.getLogger(StringMessageSink.class);
private final Session session;
private Utf8StringBuilder utf;
private int size = 0;
public StringMessageSink(Executor executor, MethodHandle methodHandle, Session session)
{
super(executor, methodHandle);
this.session = session;
// Validate onMessageMethod
Objects.requireNonNull(methodHandle, "MethodHandle");
MethodType onMessageType = MethodType.methodType(Void.TYPE, String.class);
if (methodHandle.type() != onMessageType)
{
throw InvalidSignatureException.build(onMessageType, methodHandle.type());
}
this.size = 0;
}
@SuppressWarnings("Duplicates")
@Override
public void accept(Frame frame, Callback callback)
{
try
{
if (frame.hasPayload())
{
ByteBuffer payload = frame.getPayload();
size = size + payload.remaining();
long maxMessageSize = session.getMaxTextMessageSize();
if (maxMessageSize > 0 && size > maxMessageSize)
throw new MessageTooLargeException("Message size [" + size + "] exceeds maximum size [" + maxMessageSize + "]");
if (utf == null)
utf = new Utf8StringBuilder(1024);
if (LOG.isDebugEnabled())
LOG.debug("Raw Payload {}", BufferUtil.toDetailString(payload));
// allow for fast fail of BAD utf (incomplete utf will trigger on messageComplete)
utf.append(payload);
}
if (frame.isFin())
{
// notify event
if (utf != null)
methodHandle.invoke(utf.toString());
else
methodHandle.invoke("");
// reset
size = 0;
utf = null;
}
callback.succeeded();
}
catch (Throwable t)
{
callback.failed(t);
}
}
}

View File

@ -1,117 +0,0 @@
//
// ========================================================================
// 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.common.util;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Utf8Appendable;
/**
* A CharBuffer wrapped with the Utf8Appendable logic.
*/
public class Utf8CharBuffer extends Utf8Appendable
{
/**
* Convenience method to wrap a ByteBuffer with a {@link Utf8CharBuffer}
*
* @param buffer the buffer to wrap
* @return the Utf8ByteBuffer for the provided ByteBuffer
*/
public static Utf8CharBuffer wrap(ByteBuffer buffer)
{
return new Utf8CharBuffer(buffer.asCharBuffer());
}
private final CharBuffer buffer;
private Utf8CharBuffer(CharBuffer buffer)
{
super(buffer);
this.buffer = buffer;
}
public void append(char[] cbuf, int offset, int size)
{
append(BufferUtil.toDirectBuffer(new String(cbuf, offset, size), StandardCharsets.UTF_8));
}
public void append(int c)
{
buffer.append((char)c);
}
public void clear()
{
buffer.position(0);
buffer.limit(buffer.capacity());
}
public ByteBuffer getByteBuffer()
{
// remember settings
int limit = buffer.limit();
int position = buffer.position();
// flip to flush
buffer.limit(buffer.position());
buffer.position(0);
// get byte buffer
ByteBuffer bb = StandardCharsets.UTF_8.encode(buffer);
// restor settings
buffer.limit(limit);
buffer.position(position);
return bb;
}
@Override
public int length()
{
return buffer.capacity();
}
@Override
public String getPartialString()
{
throw new UnsupportedOperationException("Cannot get Partial String from Utf8CharBuffer");
}
public int remaining()
{
return buffer.remaining();
}
@Override
public String toString()
{
StringBuilder str = new StringBuilder();
str.append("Utf8CharBuffer@").append(hashCode());
str.append("[p=").append(buffer.position());
str.append(",l=").append(buffer.limit());
str.append(",c=").append(buffer.capacity());
str.append(",r=").append(buffer.remaining());
str.append("]");
return str.toString();
}
}

View File

@ -1 +0,0 @@
org.eclipse.jetty.websocket.common.reflect.NameArgIdentifier

View File

@ -34,10 +34,12 @@ import org.eclipse.jetty.websocket.common.endpoints.annotated.MyStatelessEchoSoc
import org.eclipse.jetty.websocket.common.endpoints.annotated.NoopSocket;
import org.eclipse.jetty.websocket.common.endpoints.listeners.ListenerBasicSocket;
import org.eclipse.jetty.websocket.common.endpoints.listeners.ListenerFrameSocket;
import org.eclipse.jetty.websocket.common.message.ByteArrayMessageSink;
import org.eclipse.jetty.websocket.common.message.InputStreamMessageSink;
import org.eclipse.jetty.websocket.common.message.ReaderMessageSink;
import org.eclipse.jetty.websocket.common.message.StringMessageSink;
import org.eclipse.jetty.websocket.util.DuplicateAnnotationException;
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
import org.eclipse.jetty.websocket.util.messages.ByteArrayMessageSink;
import org.eclipse.jetty.websocket.util.messages.InputStreamMessageSink;
import org.eclipse.jetty.websocket.util.messages.ReaderMessageSink;
import org.eclipse.jetty.websocket.util.messages.StringMessageSink;
import org.hamcrest.Matcher;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
@ -94,7 +96,7 @@ public class LocalEndpointMetadataTest
public void testAnnotatedBadDuplicateFrameSocket() throws Exception
{
// Should toss exception
Exception e = assertThrows(InvalidWebSocketException.class, () -> createMetadata(BadDuplicateFrameSocket.class));
Exception e = assertThrows(DuplicateAnnotationException.class, () -> createMetadata(BadDuplicateFrameSocket.class));
assertThat(e.getMessage(), containsString("Duplicate @OnWebSocketFrame"));
}
@ -105,7 +107,7 @@ public class LocalEndpointMetadataTest
public void testAnnotatedBadSignatureNonVoidReturn() throws Exception
{
// Should toss exception
Exception e = assertThrows(InvalidWebSocketException.class, () -> createMetadata(BadBinarySignatureSocket.class));
Exception e = assertThrows(InvalidSignatureException.class, () -> createMetadata(BadBinarySignatureSocket.class));
assertThat(e.getMessage(), containsString("must be void"));
}
@ -116,7 +118,7 @@ public class LocalEndpointMetadataTest
public void testAnnotatedBadSignatureStatic() throws Exception
{
// Should toss exception
Exception e = assertThrows(InvalidWebSocketException.class, () -> createMetadata(BadTextSignatureSocket.class));
Exception e = assertThrows(InvalidSignatureException.class, () -> createMetadata(BadTextSignatureSocket.class));
assertThat(e.getMessage(), containsString("must not be static"));
}

View File

@ -28,9 +28,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.common.message.MessageInputStream;
import org.eclipse.jetty.websocket.core.Frame;
import org.eclipse.jetty.websocket.core.OpCode;
import org.eclipse.jetty.websocket.util.messages.MessageInputStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

Some files were not shown because too many files have changed in this diff Show More