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:
parent
59ae7767a4
commit
5fe202f29f
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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."))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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(")");
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<>();
|
||||
|
|
|
@ -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>"));
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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(")");
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
org.eclipse.jetty.websocket.common.reflect.NameArgIdentifier
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue