Issue #6328 - avoid binding WebSocket MethodHandles
Signed-off-by: Lachlan Roberts <lachlan.p.roberts@gmail.com>
This commit is contained in:
parent
2ba2250ac8
commit
e11120c3d1
|
@ -13,10 +13,10 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>Abstract implementation of {@link MessageSink}.</p>
|
||||
|
@ -42,21 +42,21 @@ import org.eclipse.jetty.websocket.core.CoreSession;
|
|||
public abstract class AbstractMessageSink implements MessageSink
|
||||
{
|
||||
private final CoreSession session;
|
||||
private final MethodHandle methodHandle;
|
||||
private final MethodHolder methodHandle;
|
||||
private final boolean autoDemand;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke
|
||||
* @param methodHolder the application function to invoke
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
* as explained in {@link AbstractMessageSink}
|
||||
*/
|
||||
public AbstractMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public AbstractMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
this.session = Objects.requireNonNull(session, "CoreSession");
|
||||
this.methodHandle = Objects.requireNonNull(methodHandle, "MethodHandle");
|
||||
this.methodHandle = Objects.requireNonNull(methodHolder, "MethodHolder");
|
||||
this.autoDemand = autoDemand;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ public abstract class AbstractMessageSink implements MessageSink
|
|||
* Get the application function.
|
||||
* @return the application function
|
||||
*/
|
||||
public MethodHandle getMethodHandle()
|
||||
public MethodHolder getMethodHolder()
|
||||
{
|
||||
return methodHandle;
|
||||
}
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.io.RetainableByteBuffer;
|
||||
|
@ -22,8 +20,8 @@ import org.eclipse.jetty.util.BufferUtil;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A {@link MessageSink} implementation that accumulates BINARY frames
|
||||
|
@ -38,17 +36,12 @@ public class ByteArrayMessageSink extends AbstractMessageSink
|
|||
* Creates a new {@link ByteArrayMessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke when a new message has been assembled
|
||||
* @param methodHolder the application function to invoke when a new message has been assembled
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
*/
|
||||
public ByteArrayMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public ByteArrayMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
// This uses the offset length byte array signature not supported by jakarta websocket.
|
||||
// The jakarta layer instead uses decoders for whole byte array messages instead of this message sink.
|
||||
MethodType onMessageType = MethodType.methodType(Void.TYPE, byte[].class, int.class, int.class);
|
||||
if (methodHandle.type().changeReturnType(void.class) != onMessageType.changeReturnType(void.class))
|
||||
throw InvalidSignatureException.build(onMessageType, methodHandle.type());
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -70,7 +63,7 @@ public class ByteArrayMessageSink extends AbstractMessageSink
|
|||
if (frame.isFin() && (accumulator == null || accumulator.isEmpty()))
|
||||
{
|
||||
byte[] buf = BufferUtil.toArray(payload);
|
||||
getMethodHandle().invoke(buf, 0, buf.length);
|
||||
getMethodHolder().invoke(buf, 0, buf.length);
|
||||
callback.succeeded();
|
||||
autoDemand();
|
||||
return;
|
||||
|
@ -93,7 +86,7 @@ public class ByteArrayMessageSink extends AbstractMessageSink
|
|||
callback = Callback.NOOP;
|
||||
int length = accumulator.remaining();
|
||||
byte[] buf = accumulator.takeByteArray();
|
||||
getMethodHandle().invoke(buf, 0, length);
|
||||
getMethodHolder().invoke(buf, 0, length);
|
||||
autoDemand();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferCallbackAccumulator;
|
||||
|
@ -23,8 +21,8 @@ import org.eclipse.jetty.io.RetainableByteBuffer;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A {@link MessageSink} implementation that accumulates BINARY frames
|
||||
|
@ -39,24 +37,12 @@ public class ByteBufferMessageSink extends AbstractMessageSink
|
|||
* Creates a new {@link ByteBufferMessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke when a new message has been assembled
|
||||
* @param methodHolder the application function to invoke when a new message has been assembled
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
*/
|
||||
public ByteBufferMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public ByteBufferMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
this(session, methodHandle, autoDemand, true);
|
||||
}
|
||||
|
||||
protected ByteBufferMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand, boolean validateSignature)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
|
||||
if (validateSignature)
|
||||
{
|
||||
MethodType onMessageType = MethodType.methodType(Void.TYPE, ByteBuffer.class);
|
||||
if (methodHandle.type() != onMessageType)
|
||||
throw InvalidSignatureException.build(onMessageType, methodHandle.type());
|
||||
}
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,7 +62,7 @@ public class ByteBufferMessageSink extends AbstractMessageSink
|
|||
// created or used, then we don't need to aggregate.
|
||||
if (frame.isFin() && (accumulator == null || accumulator.getLength() == 0))
|
||||
{
|
||||
invoke(getMethodHandle(), frame.getPayload(), callback);
|
||||
invoke(getMethodHolder(), frame.getPayload(), callback);
|
||||
autoDemand();
|
||||
return;
|
||||
}
|
||||
|
@ -99,7 +85,7 @@ public class ByteBufferMessageSink extends AbstractMessageSink
|
|||
ByteBuffer byteBuffer = buffer.getByteBuffer();
|
||||
accumulator.writeTo(byteBuffer);
|
||||
callback = Callback.from(buffer::release);
|
||||
invoke(getMethodHandle(), byteBuffer, callback);
|
||||
invoke(getMethodHolder(), byteBuffer, callback);
|
||||
autoDemand();
|
||||
}
|
||||
else
|
||||
|
@ -122,9 +108,9 @@ public class ByteBufferMessageSink extends AbstractMessageSink
|
|||
accumulator.fail(failure);
|
||||
}
|
||||
|
||||
protected void invoke(MethodHandle methodHandle, ByteBuffer byteBuffer, Callback callback) throws Throwable
|
||||
protected void invoke(MethodHolder methodHolder, ByteBuffer byteBuffer, Callback callback) throws Throwable
|
||||
{
|
||||
methodHandle.invoke(byteBuffer);
|
||||
methodHolder.invoke(byteBuffer);
|
||||
callback.succeeded();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.websocket.core.messages;
|
|||
import java.io.Closeable;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
@ -26,6 +25,7 @@ import org.eclipse.jetty.util.IO;
|
|||
import org.eclipse.jetty.websocket.core.CloseStatus;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A partial implementation of {@link MessageSink} for methods that consume WebSocket
|
||||
|
@ -51,9 +51,9 @@ public abstract class DispatchedMessageSink extends AbstractMessageSink
|
|||
private volatile CompletableFuture<Void> dispatchComplete;
|
||||
private MessageSink typeSink;
|
||||
|
||||
public DispatchedMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public DispatchedMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
if (!autoDemand)
|
||||
throw new IllegalArgumentException("%s must be auto-demanding".formatted(getClass().getSimpleName()));
|
||||
executor = session.getWebSocketComponents().getExecutor();
|
||||
|
@ -74,7 +74,7 @@ public abstract class DispatchedMessageSink extends AbstractMessageSink
|
|||
{
|
||||
try
|
||||
{
|
||||
getMethodHandle().invoke(typeSink);
|
||||
getMethodHolder().invoke(typeSink);
|
||||
if (typeSink instanceof Closeable closeable)
|
||||
IO.close(closeable);
|
||||
dispatchComplete.complete(null);
|
||||
|
|
|
@ -13,15 +13,14 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class InputStreamMessageSink extends DispatchedMessageSink
|
||||
{
|
||||
public InputStreamMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public InputStreamMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,12 +13,11 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A {@link MessageSink} implementation that delivers BINARY frames
|
||||
|
@ -31,12 +30,12 @@ public class PartialByteArrayMessageSink extends AbstractMessageSink
|
|||
* Creates a new {@link PartialByteArrayMessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke when a new frame has arrived
|
||||
* @param methodHolder the application function to invoke when a new frame has arrived
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
*/
|
||||
public PartialByteArrayMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public PartialByteArrayMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,7 +46,7 @@ public class PartialByteArrayMessageSink extends AbstractMessageSink
|
|||
if (frame.hasPayload() || frame.isFin())
|
||||
{
|
||||
byte[] buffer = BufferUtil.toArray(frame.getPayload());
|
||||
getMethodHandle().invoke(buffer, frame.isFin());
|
||||
getMethodHolder().invoke(buffer, frame.isFin());
|
||||
callback.succeeded();
|
||||
autoDemand();
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A {@link MessageSink} implementation that delivers BINARY frames
|
||||
|
@ -31,12 +31,12 @@ public class PartialByteBufferMessageSink extends AbstractMessageSink
|
|||
* Creates a new {@link PartialByteBufferMessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke when a new frame has arrived
|
||||
* @param methodHolder the application function to invoke when a new frame has arrived
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
*/
|
||||
public PartialByteBufferMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public PartialByteBufferMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +46,7 @@ public class PartialByteBufferMessageSink extends AbstractMessageSink
|
|||
{
|
||||
if (frame.hasPayload() || frame.isFin())
|
||||
{
|
||||
invoke(getMethodHandle(), frame.getPayload(), frame.isFin(), callback);
|
||||
invoke(getMethodHolder(), frame.getPayload(), frame.isFin(), callback);
|
||||
autoDemand();
|
||||
}
|
||||
else
|
||||
|
@ -61,9 +61,9 @@ public class PartialByteBufferMessageSink extends AbstractMessageSink
|
|||
}
|
||||
}
|
||||
|
||||
protected void invoke(MethodHandle methodHandle, ByteBuffer byteBuffer, boolean fin, Callback callback) throws Throwable
|
||||
protected void invoke(MethodHolder methodHolder, ByteBuffer byteBuffer, boolean fin, Callback callback) throws Throwable
|
||||
{
|
||||
methodHandle.invoke(byteBuffer, fin);
|
||||
methodHolder.invoke(byteBuffer, fin);
|
||||
callback.succeeded();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,12 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
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.exception.BadPayloadException;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A {@link MessageSink} implementation that delivers TEXT frames
|
||||
|
@ -34,12 +33,12 @@ public class PartialStringMessageSink extends AbstractMessageSink
|
|||
* Creates a new {@link PartialStringMessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke when a new frame has arrived
|
||||
* @param methodHolder the application function to invoke when a new frame has arrived
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
*/
|
||||
public PartialStringMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public PartialStringMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -55,12 +54,12 @@ public class PartialStringMessageSink extends AbstractMessageSink
|
|||
if (frame.isFin())
|
||||
{
|
||||
String complete = accumulator.takeCompleteString(BadPayloadException.InvalidUtf8::new);
|
||||
getMethodHandle().invoke(complete, true);
|
||||
getMethodHolder().invoke(complete, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
String partial = accumulator.takePartialString(BadPayloadException.InvalidUtf8::new);
|
||||
getMethodHandle().invoke(partial, false);
|
||||
getMethodHolder().invoke(partial, false);
|
||||
}
|
||||
|
||||
callback.succeeded();
|
||||
|
|
|
@ -13,15 +13,14 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class ReaderMessageSink extends DispatchedMessageSink
|
||||
{
|
||||
public ReaderMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public ReaderMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,14 +13,13 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
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.exception.BadPayloadException;
|
||||
import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
/**
|
||||
* <p>A {@link MessageSink} implementation that accumulates TEXT frames
|
||||
|
@ -36,12 +35,12 @@ public class StringMessageSink extends AbstractMessageSink
|
|||
* Creates a new {@link StringMessageSink}.
|
||||
*
|
||||
* @param session the WebSocket session
|
||||
* @param methodHandle the application function to invoke when a new message has been assembled
|
||||
* @param methodHolder the application function to invoke when a new message has been assembled
|
||||
* @param autoDemand whether this {@link MessageSink} manages demand automatically
|
||||
*/
|
||||
public StringMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public StringMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
super(session, methodHolder, autoDemand);
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,7 @@ public class StringMessageSink extends AbstractMessageSink
|
|||
|
||||
if (frame.isFin())
|
||||
{
|
||||
getMethodHandle().invoke(out.takeCompleteString(BadPayloadException.InvalidUtf8::new));
|
||||
getMethodHolder().invoke(out.takeCompleteString(BadPayloadException.InvalidUtf8::new));
|
||||
reset();
|
||||
callback.succeeded();
|
||||
autoDemand();
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.core.util;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
class BindingMethodHolder implements MethodHolder
|
||||
{
|
||||
public MethodHandle _methodHandle;
|
||||
|
||||
public BindingMethodHolder(MethodHandle methodHandle)
|
||||
{
|
||||
_methodHandle = methodHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
return MethodHolder.doInvoke(_methodHandle, args);
|
||||
}
|
||||
|
||||
public MethodHandle getMethodHandler()
|
||||
{
|
||||
return _methodHandle;
|
||||
}
|
||||
|
||||
public Object invoke(Object o1, Object o2) throws Throwable
|
||||
{
|
||||
return MethodHolder.doInvoke(_methodHandle, o1, o2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindingMethodHolder bindTo(Object arg)
|
||||
{
|
||||
_methodHandle = _methodHandle.bindTo(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHolder bindTo(Object arg, int idx)
|
||||
{
|
||||
_methodHandle = MethodHandles.insertArguments(_methodHandle, idx, arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
return _methodHandle.type().parameterType(idx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return _methodHandle.type().returnType();
|
||||
}
|
||||
}
|
|
@ -135,18 +135,18 @@ public class InvokerUtils
|
|||
/**
|
||||
* Bind optional arguments to provided method handle
|
||||
*
|
||||
* @param methodHandle the method handle to bind to
|
||||
* @param methodHolder the method handle to bind to
|
||||
* @param objs the list of optional objects to bind to.
|
||||
* @return the bound MethodHandle, or null if the provided {@code methodHandle} was null.
|
||||
* @return the bound MethodHandle, or null if the provided {@code methodHolder} was null.
|
||||
*/
|
||||
public static MethodHandle bindTo(MethodHandle methodHandle, Object... objs)
|
||||
public static MethodHolder bindTo(MethodHolder methodHolder, Object... objs)
|
||||
{
|
||||
if (methodHandle == null)
|
||||
if (methodHolder == null)
|
||||
return null;
|
||||
MethodHandle ret = methodHandle;
|
||||
MethodHolder ret = methodHolder;
|
||||
for (Object obj : objs)
|
||||
{
|
||||
if (ret.type().parameterType(0).isAssignableFrom(obj.getClass()))
|
||||
if (ret.parameterType(0).isAssignableFrom(obj.getClass()))
|
||||
{
|
||||
ret = ret.bindTo(obj);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.core.util;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
|
||||
/**
|
||||
* An interface for managing invocations of methods whose arguments may need to be augmented, by
|
||||
* binding in certain parameters ahead of time.
|
||||
*
|
||||
* Implementations may use various invocation mechanisms, including:
|
||||
* <ul>
|
||||
* <li>direct method invocation on an held object</li>
|
||||
* <li>calling a method pointer</li>
|
||||
* <li>calling a MethodHandle bound to the known arguments</li>
|
||||
* <li>calling a MethodHandle without binding to the known arguments</li>
|
||||
* </ul>
|
||||
*
|
||||
* Implementations of this may not be thread safe, so the caller must use some external mutual exclusion
|
||||
* unless they are using a specific implementation known to be thread-safe.
|
||||
*/
|
||||
public interface MethodHolder
|
||||
{
|
||||
String METHOD_HOLDER_BINDING_PROPERTY = "jetty.websocket.methodholder.binding";
|
||||
|
||||
static MethodHolder from(MethodHandle methodHandle)
|
||||
{
|
||||
String property = System.getProperty(METHOD_HOLDER_BINDING_PROPERTY);
|
||||
return from(methodHandle, Boolean.parseBoolean(property));
|
||||
}
|
||||
|
||||
static MethodHolder from(MethodHandle methodHandle, boolean binding)
|
||||
{
|
||||
if (methodHandle == null)
|
||||
return null;
|
||||
return binding ? new BindingMethodHolder(methodHandle) : new NonBindingMethodHolder(methodHandle);
|
||||
}
|
||||
|
||||
Object invoke(Object... args) throws Throwable;
|
||||
|
||||
default MethodHolder bindTo(Object arg)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
default MethodHolder bindTo(Object arg, int idx)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
default Class<?> parameterType(int idx)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
default Class<?> returnType()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
static Object doInvoke(MethodHandle methodHandle, Object arg1, Object arg2) throws Throwable
|
||||
{
|
||||
return methodHandle.invoke(arg1, arg2);
|
||||
}
|
||||
|
||||
static Object doInvoke(MethodHandle methodHandle, Object... args) throws Throwable
|
||||
{
|
||||
switch (args.length)
|
||||
{
|
||||
case 0:
|
||||
return methodHandle.invoke();
|
||||
case 1:
|
||||
return methodHandle.invoke(args[0]);
|
||||
case 2:
|
||||
return methodHandle.invoke(args[0], args[1]);
|
||||
case 3:
|
||||
return methodHandle.invoke(args[0], args[1], args[2]);
|
||||
case 4:
|
||||
return methodHandle.invoke(args[0], args[1], args[2], args[3]);
|
||||
case 5:
|
||||
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4]);
|
||||
case 6:
|
||||
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5]);
|
||||
case 7:
|
||||
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
||||
case 8:
|
||||
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
|
||||
case 9:
|
||||
return methodHandle.invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
|
||||
default:
|
||||
return methodHandle.invokeWithArguments(args);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.core.util;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This implementation of {@link MethodHolder} is not thread safe.
|
||||
* Mutual exclusion should be used when calling {@link #invoke(Object...)}, or this should only
|
||||
* be invoked from a single thread.
|
||||
*/
|
||||
class NonBindingMethodHolder implements MethodHolder
|
||||
{
|
||||
private final MethodHandle _methodHandle;
|
||||
private final Object[] _parameters;
|
||||
private final List<Integer> _unboundParamIndexes = new ArrayList<>();
|
||||
|
||||
public NonBindingMethodHolder(MethodHandle methodHandle)
|
||||
{
|
||||
_methodHandle = Objects.requireNonNull(methodHandle);
|
||||
int numParams = methodHandle.type().parameterCount();
|
||||
_parameters = new Object[numParams];
|
||||
for (int i = 0; i < numParams; i++)
|
||||
{
|
||||
_unboundParamIndexes.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
try
|
||||
{
|
||||
insertArguments(args);
|
||||
return MethodHolder.doInvoke(_methodHandle, _parameters);
|
||||
}
|
||||
finally
|
||||
{
|
||||
clearArguments();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHolder bindTo(Object arg, int idx)
|
||||
{
|
||||
_parameters[_unboundParamIndexes.get(idx)] = arg;
|
||||
_unboundParamIndexes.remove(idx);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHolder bindTo(Object arg)
|
||||
{
|
||||
return bindTo(arg, 0);
|
||||
}
|
||||
|
||||
private void insertArguments(Object... args)
|
||||
{
|
||||
if (_unboundParamIndexes.size() != args.length)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", _unboundParamIndexes.size(), args.length));
|
||||
|
||||
int argsIndex = 0;
|
||||
for (int index : _unboundParamIndexes)
|
||||
{
|
||||
_parameters[index] = args[argsIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
private void clearArguments()
|
||||
{
|
||||
for (int i : _unboundParamIndexes)
|
||||
{
|
||||
_parameters[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
return _methodHandle.type().parameterType(_unboundParamIndexes.get(idx));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return _methodHandle.type().returnType();
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ public class PartialStringMessageSinkTest
|
|||
@BeforeEach
|
||||
public void before() throws Exception
|
||||
{
|
||||
messageSink = new PartialStringMessageSink(coreSession, endpoint.getMethodHandle(), true);
|
||||
messageSink = new PartialStringMessageSink(coreSession, MethodHolder.from(endpoint.getMethodHandle()), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -38,13 +38,13 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
|
||||
public class StringMessageSinkTest
|
||||
{
|
||||
private CoreSession coreSession = new CoreSession.Empty();
|
||||
private OnMessageEndpoint endpoint = new OnMessageEndpoint();
|
||||
private final CoreSession coreSession = new CoreSession.Empty();
|
||||
private final OnMessageEndpoint endpoint = new OnMessageEndpoint();
|
||||
|
||||
@Test
|
||||
public void testMaxMessageSize() throws Exception
|
||||
{
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, endpoint.getMethodHandle(), true);
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, MethodHolder.from(endpoint.getMethodHandle()), true);
|
||||
ByteBuffer utf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0xF0, (byte)0x90, (byte)0x8D, (byte)0x88});
|
||||
|
||||
FutureCallback callback = new FutureCallback();
|
||||
|
@ -60,7 +60,7 @@ public class StringMessageSinkTest
|
|||
@Test
|
||||
public void testValidUtf8() throws Exception
|
||||
{
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, endpoint.getMethodHandle(), true);
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, MethodHolder.from(endpoint.getMethodHandle()), true);
|
||||
ByteBuffer utf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0xF0, (byte)0x90, (byte)0x8D, (byte)0x88});
|
||||
|
||||
FutureCallback callback = new FutureCallback();
|
||||
|
@ -73,7 +73,7 @@ public class StringMessageSinkTest
|
|||
@Test
|
||||
public void testUtf8Continuation() throws Exception
|
||||
{
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, endpoint.getMethodHandle(), true);
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, MethodHolder.from(endpoint.getMethodHandle()), true);
|
||||
ByteBuffer firstUtf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0xF0, (byte)0x90});
|
||||
ByteBuffer continuationUtf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0x8D, (byte)0x88});
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class StringMessageSinkTest
|
|||
@Test
|
||||
public void testInvalidSingleFrameUtf8() throws Exception
|
||||
{
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, endpoint.getMethodHandle(), true);
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, MethodHolder.from(endpoint.getMethodHandle()), true);
|
||||
ByteBuffer invalidUtf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0xF0, (byte)0x90, (byte)0x8D});
|
||||
|
||||
FutureCallback callback = new FutureCallback();
|
||||
|
@ -106,7 +106,7 @@ public class StringMessageSinkTest
|
|||
@Test
|
||||
public void testInvalidMultiFrameUtf8() throws Exception
|
||||
{
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, endpoint.getMethodHandle(), true);
|
||||
StringMessageSink messageSink = new StringMessageSink(coreSession, MethodHolder.from(endpoint.getMethodHandle()), true);
|
||||
ByteBuffer firstUtf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0xF0, (byte)0x90});
|
||||
ByteBuffer continuationUtf8Payload = BufferUtil.toBuffer(new byte[]{(byte)0x8D});
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ import org.eclipse.jetty.websocket.core.exception.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.core.exception.WebSocketTimeoutException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -52,16 +53,16 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
private final WebSocketContainer container;
|
||||
private final Object endpointInstance;
|
||||
private final JettyWebSocketFrameHandlerMetadata metadata;
|
||||
private MethodHandle openHandle;
|
||||
private MethodHandle closeHandle;
|
||||
private MethodHandle errorHandle;
|
||||
private MethodHandle textHandle;
|
||||
private MethodHandle binaryHandle;
|
||||
private MethodHolder openHandle;
|
||||
private MethodHolder closeHandle;
|
||||
private MethodHolder errorHandle;
|
||||
private MethodHolder textHandle;
|
||||
private MethodHolder binaryHandle;
|
||||
private final Class<? extends MessageSink> textSinkClass;
|
||||
private final Class<? extends MessageSink> binarySinkClass;
|
||||
private MethodHandle frameHandle;
|
||||
private MethodHandle pingHandle;
|
||||
private MethodHandle pongHandle;
|
||||
private MethodHolder frameHandle;
|
||||
private MethodHolder pingHandle;
|
||||
private MethodHolder pongHandle;
|
||||
private UpgradeRequest upgradeRequest;
|
||||
private UpgradeResponse upgradeResponse;
|
||||
private MessageSink textSink;
|
||||
|
@ -76,16 +77,16 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
this.endpointInstance = endpointInstance;
|
||||
this.metadata = metadata;
|
||||
|
||||
this.openHandle = InvokerUtils.bindTo(metadata.getOpenHandle(), endpointInstance);
|
||||
this.closeHandle = InvokerUtils.bindTo(metadata.getCloseHandle(), endpointInstance);
|
||||
this.errorHandle = InvokerUtils.bindTo(metadata.getErrorHandle(), endpointInstance);
|
||||
this.textHandle = InvokerUtils.bindTo(metadata.getTextHandle(), endpointInstance);
|
||||
this.binaryHandle = InvokerUtils.bindTo(metadata.getBinaryHandle(), endpointInstance);
|
||||
this.openHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getOpenHandle()), endpointInstance);
|
||||
this.closeHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getCloseHandle()), endpointInstance);
|
||||
this.errorHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getErrorHandle()), endpointInstance);
|
||||
this.textHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getTextHandle()), endpointInstance);
|
||||
this.binaryHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getBinaryHandle()), endpointInstance);
|
||||
this.textSinkClass = metadata.getTextSink();
|
||||
this.binarySinkClass = metadata.getBinarySink();
|
||||
this.frameHandle = InvokerUtils.bindTo(metadata.getFrameHandle(), endpointInstance);
|
||||
this.pingHandle = InvokerUtils.bindTo(metadata.getPingHandle(), endpointInstance);
|
||||
this.pongHandle = InvokerUtils.bindTo(metadata.getPongHandle(), endpointInstance);
|
||||
this.frameHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getFrameHandle()), endpointInstance);
|
||||
this.pingHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getPingHandle()), endpointInstance);
|
||||
this.pongHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getPongHandle()), endpointInstance);
|
||||
}
|
||||
|
||||
public void setUpgradeRequest(UpgradeRequest upgradeRequest)
|
||||
|
@ -157,7 +158,7 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
}
|
||||
}
|
||||
|
||||
private static MessageSink createMessageSink(Class<? extends MessageSink> sinkClass, WebSocketSession session, MethodHandle msgHandle, boolean autoDemanding)
|
||||
private static MessageSink createMessageSink(Class<? extends MessageSink> sinkClass, WebSocketSession session, MethodHolder msgHandle, boolean autoDemanding)
|
||||
{
|
||||
if (msgHandle == null)
|
||||
return null;
|
||||
|
@ -168,7 +169,7 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
{
|
||||
MethodHandles.Lookup lookup = JettyWebSocketFrameHandlerFactory.getServerMethodHandleLookup();
|
||||
MethodHandle ctorHandle = lookup.findConstructor(sinkClass,
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, boolean.class));
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgHandle, autoDemanding);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
|
|
@ -13,28 +13,22 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.internal;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class ByteBufferMessageSink extends org.eclipse.jetty.websocket.core.messages.ByteBufferMessageSink
|
||||
{
|
||||
public ByteBufferMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public ByteBufferMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand, false);
|
||||
|
||||
MethodType onMessageType = MethodType.methodType(Void.TYPE, ByteBuffer.class, Callback.class);
|
||||
if (methodHandle.type() != onMessageType)
|
||||
throw InvalidSignatureException.build(onMessageType, methodHandle.type());
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(MethodHandle methodHandle, ByteBuffer byteBuffer, org.eclipse.jetty.util.Callback callback) throws Throwable
|
||||
protected void invoke(MethodHolder methodHolder, ByteBuffer byteBuffer, org.eclipse.jetty.util.Callback callback) throws Throwable
|
||||
{
|
||||
methodHandle.invoke(byteBuffer, Callback.from(callback::succeeded, callback::failed));
|
||||
methodHolder.invoke(byteBuffer, Callback.from(callback::succeeded, callback::failed));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,28 +13,22 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.internal;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Callback;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class PartialByteBufferMessageSink extends org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink
|
||||
{
|
||||
public PartialByteBufferMessageSink(CoreSession session, MethodHandle methodHandle, boolean autoDemand)
|
||||
public PartialByteBufferMessageSink(CoreSession session, MethodHolder methodHolder, boolean autoDemand)
|
||||
{
|
||||
super(session, methodHandle, autoDemand);
|
||||
|
||||
MethodType onMessageType = MethodType.methodType(Void.TYPE, ByteBuffer.class, boolean.class, Callback.class);
|
||||
if (methodHandle.type() != onMessageType)
|
||||
throw InvalidSignatureException.build(onMessageType, methodHandle.type());
|
||||
super(session, methodHolder, autoDemand);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(MethodHandle methodHandle, ByteBuffer byteBuffer, boolean fin, org.eclipse.jetty.util.Callback callback) throws Throwable
|
||||
protected void invoke(MethodHolder methodHolder, ByteBuffer byteBuffer, boolean fin, org.eclipse.jetty.util.Callback callback) throws Throwable
|
||||
{
|
||||
methodHandle.invoke(byteBuffer, fin, Callback.from(callback::succeeded, callback::failed));
|
||||
methodHolder.invoke(byteBuffer, fin, Callback.from(callback::succeeded, callback::failed));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.websocket.core.Frame;
|
|||
import org.eclipse.jetty.websocket.core.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -96,7 +97,7 @@ public class OutgoingMessageCapture extends CoreSession.Empty implements CoreSes
|
|||
String event = String.format("TEXT:fin=%b:len=%d", frame.isFin(), frame.getPayloadLength());
|
||||
LOG.debug(event);
|
||||
events.offer(event);
|
||||
messageSink = new StringMessageSink(this, wholeTextHandle, true);
|
||||
messageSink = new StringMessageSink(this, MethodHolder.from(wholeTextHandle), true);
|
||||
break;
|
||||
}
|
||||
case OpCode.BINARY:
|
||||
|
@ -104,7 +105,7 @@ public class OutgoingMessageCapture extends CoreSession.Empty implements CoreSes
|
|||
String event = String.format("BINARY:fin=%b:len=%d", frame.isFin(), frame.getPayloadLength());
|
||||
LOG.debug(event);
|
||||
events.offer(event);
|
||||
messageSink = new ByteBufferMessageSink(this, wholeBinaryHandle, true);
|
||||
messageSink = new ByteBufferMessageSink(this, MethodHolder.from(wholeBinaryHandle), true);
|
||||
break;
|
||||
}
|
||||
case OpCode.CONTINUATION:
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.ee10.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
class JakartaMessagePartialMethodHolder<T> implements MethodHolder
|
||||
{
|
||||
private final MessageHandler.Partial<T> _messageHandler;
|
||||
|
||||
public JakartaMessagePartialMethodHolder(MessageHandler.Partial<T> messageHandler)
|
||||
{
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
if (args.length != 2)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 2, args.length));
|
||||
_messageHandler.onMessage((T)args[0], (boolean)args[1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return Object.class;
|
||||
case 1:
|
||||
return boolean.class;
|
||||
default:
|
||||
throw new IndexOutOfBoundsException(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return void.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.ee10.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
class JakartaMessageWholeMethodHolder<T> implements MethodHolder
|
||||
{
|
||||
private final MessageHandler.Whole<T> _messageHandler;
|
||||
|
||||
public JakartaMessageWholeMethodHolder(MessageHandler.Whole<T> messageHandler)
|
||||
{
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
_messageHandler.onMessage((T)args[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return Object.class;
|
||||
default:
|
||||
throw new IndexOutOfBoundsException(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return void.class;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -51,6 +49,7 @@ import org.eclipse.jetty.websocket.core.messages.PartialByteArrayMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -62,10 +61,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
private final Object endpointInstance;
|
||||
private final AtomicBoolean closeNotified = new AtomicBoolean();
|
||||
|
||||
private MethodHandle openHandle;
|
||||
private MethodHandle closeHandle;
|
||||
private MethodHandle errorHandle;
|
||||
private MethodHandle pongHandle;
|
||||
private MethodHolder openHandle;
|
||||
private MethodHolder closeHandle;
|
||||
private MethodHolder errorHandle;
|
||||
private MethodHolder pongHandle;
|
||||
private JakartaWebSocketMessageMetadata textMetadata;
|
||||
private JakartaWebSocketMessageMetadata binaryMetadata;
|
||||
private final UpgradeRequest upgradeRequest;
|
||||
|
@ -79,12 +78,12 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
protected byte dataType = OpCode.UNDEFINED;
|
||||
|
||||
public JakartaWebSocketFrameHandler(JakartaWebSocketContainer container,
|
||||
UpgradeRequest upgradeRequest,
|
||||
UpgradeRequest upgradeRequest,
|
||||
Object endpointInstance,
|
||||
MethodHandle openHandle, MethodHandle closeHandle, MethodHandle errorHandle,
|
||||
JakartaWebSocketMessageMetadata textMetadata,
|
||||
JakartaWebSocketMessageMetadata binaryMetadata,
|
||||
MethodHandle pongHandle,
|
||||
MethodHolder openHandle, MethodHolder closeHandle, MethodHolder errorHandle,
|
||||
JakartaWebSocketMessageMetadata textMetadata,
|
||||
JakartaWebSocketMessageMetadata binaryMetadata,
|
||||
MethodHolder pongHandle,
|
||||
EndpointConfig endpointConfig)
|
||||
{
|
||||
this.logger = LoggerFactory.getLogger(endpointInstance.getClass());
|
||||
|
@ -147,10 +146,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
if (actualTextMetadata.isMaxMessageSizeSet())
|
||||
session.setMaxTextMessageBufferSize(actualTextMetadata.getMaxMessageSize());
|
||||
|
||||
MethodHandle methodHandle = actualTextMetadata.getMethodHandle();
|
||||
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||
actualTextMetadata.setMethodHandle(methodHandle);
|
||||
MethodHolder methodHolder = actualTextMetadata.getMethodHolder();
|
||||
methodHolder = InvokerUtils.bindTo(methodHolder, endpointInstance, endpointConfig, session);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHolder, session);
|
||||
actualTextMetadata.setMethodHolder(methodHolder);
|
||||
|
||||
textSink = JakartaWebSocketFrameHandlerFactory.createMessageSink(session, actualTextMetadata);
|
||||
textMetadata = actualTextMetadata;
|
||||
|
@ -162,10 +161,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
if (actualBinaryMetadata.isMaxMessageSizeSet())
|
||||
session.setMaxBinaryMessageBufferSize(actualBinaryMetadata.getMaxMessageSize());
|
||||
|
||||
MethodHandle methodHandle = actualBinaryMetadata.getMethodHandle();
|
||||
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||
actualBinaryMetadata.setMethodHandle(methodHandle);
|
||||
MethodHolder methodHolder = actualBinaryMetadata.getMethodHolder();
|
||||
methodHolder = InvokerUtils.bindTo(methodHolder, endpointInstance, endpointConfig, session);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHolder, session);
|
||||
actualBinaryMetadata.setMethodHolder(methodHolder);
|
||||
|
||||
binarySink = JakartaWebSocketFrameHandlerFactory.createMessageSink(session, actualBinaryMetadata);
|
||||
binaryMetadata = actualBinaryMetadata;
|
||||
|
@ -346,116 +345,88 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
|
||||
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
|
||||
{
|
||||
try
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHolder(new JakartaMessagePartialMethodHolder<>(handler));
|
||||
byte basicType;
|
||||
// MessageHandler.Partial has no decoder support!
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(MessageHandler.Partial.class, "onMessage", MethodType.methodType(void.class, Object.class, boolean.class))
|
||||
.bindTo(handler);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
}
|
||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
}
|
||||
else if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Unable to add " + handler.getClass().getName() + " with type " + clazz + ": only supported types byte[], " + ByteBuffer.class.getName() +
|
||||
", " + String.class.getName());
|
||||
}
|
||||
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHandle(methodHandle);
|
||||
byte basicType;
|
||||
// MessageHandler.Partial has no decoder support!
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
}
|
||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
}
|
||||
else if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Unable to add " + handler.getClass().getName() + " with type " + clazz + ": only supported types byte[], " + ByteBuffer.class.getName() +
|
||||
", " + String.class.getName());
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to find method", e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to access " + handler.getClass().getName(), e);
|
||||
}
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
|
||||
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
|
||||
{
|
||||
try
|
||||
MethodHolder methodHolder = new JakartaMessageWholeMethodHolder<>(handler);
|
||||
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class))
|
||||
.bindTo(handler);
|
||||
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
assertBasicTypeNotRegistered(OpCode.PONG, handler);
|
||||
this.pongHandle = methodHandle;
|
||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||
return;
|
||||
}
|
||||
|
||||
AvailableDecoders availableDecoders = session.getDecoders();
|
||||
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||
if (registeredDecoder == null)
|
||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||
|
||||
// Create the message metadata specific to the MessageHandler type.
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHandle(methodHandle);
|
||||
byte basicType;
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Unable to add " + handler.getClass().getName() + ": type " + clazz + " is unrecognized by declared decoders");
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
assertBasicTypeNotRegistered(OpCode.PONG, handler);
|
||||
this.pongHandle = methodHolder;
|
||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||
return;
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
||||
AvailableDecoders availableDecoders = session.getDecoders();
|
||||
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||
if (registeredDecoder == null)
|
||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||
|
||||
// Create the message metadata specific to the MessageHandler type.
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHolder(methodHolder);
|
||||
byte basicType;
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
throw new IllegalStateException("Unable to find method", e);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
throw new IllegalStateException("Unable to access " + handler.getClass().getName(), e);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Unable to add " + handler.getClass().getName() + ": type " + clazz + " is unrecognized by declared decoders");
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
|
||||
private void assertBasicTypeNotRegistered(byte basicWebSocketType, MessageHandler replacement)
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.eclipse.jetty.websocket.core.messages.PartialByteArrayMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
|
||||
public abstract class JakartaWebSocketFrameHandlerFactory
|
||||
|
@ -135,10 +136,10 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (metadata == null)
|
||||
return null;
|
||||
|
||||
MethodHandle openHandle = metadata.getOpenHandle();
|
||||
MethodHandle closeHandle = metadata.getCloseHandle();
|
||||
MethodHandle errorHandle = metadata.getErrorHandle();
|
||||
MethodHandle pongHandle = metadata.getPongHandle();
|
||||
MethodHolder openHandle = MethodHolder.from(metadata.getOpenHandle());
|
||||
MethodHolder closeHandle = MethodHolder.from(metadata.getCloseHandle());
|
||||
MethodHolder errorHandle = MethodHolder.from(metadata.getErrorHandle());
|
||||
MethodHolder pongHandle = MethodHolder.from(metadata.getPongHandle());
|
||||
|
||||
JakartaWebSocketMessageMetadata textMetadata = JakartaWebSocketMessageMetadata.copyOf(metadata.getTextMetadata());
|
||||
JakartaWebSocketMessageMetadata binaryMetadata = JakartaWebSocketMessageMetadata.copyOf(metadata.getBinaryMetadata());
|
||||
|
@ -156,9 +157,9 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
pongHandle = bindTemplateVariables(pongHandle, namedVariables, pathParams);
|
||||
|
||||
if (textMetadata != null)
|
||||
textMetadata.setMethodHandle(bindTemplateVariables(textMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||
textMetadata.setMethodHolder(bindTemplateVariables(textMetadata.getMethodHolder(), namedVariables, pathParams));
|
||||
if (binaryMetadata != null)
|
||||
binaryMetadata.setMethodHandle(bindTemplateVariables(binaryMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||
binaryMetadata.setMethodHolder(bindTemplateVariables(binaryMetadata.getMethodHolder(), namedVariables, pathParams));
|
||||
}
|
||||
|
||||
openHandle = InvokerUtils.bindTo(openHandle, endpoint);
|
||||
|
@ -190,15 +191,15 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (AbstractDecodedMessageSink.class.isAssignableFrom(msgMetadata.getSinkClass()))
|
||||
{
|
||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, List.class));
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, List.class));
|
||||
List<RegisteredDecoder> registeredDecoders = msgMetadata.getRegisteredDecoders();
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), registeredDecoders);
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHolder(), registeredDecoders);
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), true);
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHolder(), true);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
@ -219,23 +220,19 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
}
|
||||
}
|
||||
|
||||
public static MethodHandle wrapNonVoidReturnType(MethodHandle handle, JakartaWebSocketSession session)
|
||||
public static MethodHolder wrapNonVoidReturnType(MethodHolder handle, JakartaWebSocketSession session)
|
||||
{
|
||||
if (handle == null)
|
||||
return null;
|
||||
|
||||
if (handle.type().returnType() == Void.TYPE)
|
||||
if (handle.returnType() == Void.TYPE)
|
||||
return handle;
|
||||
|
||||
// Technique from https://stackoverflow.com/questions/48505787/methodhandle-with-general-non-void-return-filter
|
||||
|
||||
// Change the return type of the to be Object so it will match exact with JakartaWebSocketSession.filterReturnType(Object)
|
||||
handle = handle.asType(handle.type().changeReturnType(Object.class));
|
||||
|
||||
// Filter the method return type to a call to JakartaWebSocketSession.filterReturnType() bound to this session
|
||||
handle = MethodHandles.filterReturnValue(handle, FILTER_RETURN_TYPE_METHOD.bindTo(session));
|
||||
|
||||
return handle;
|
||||
return args ->
|
||||
{
|
||||
session.filterReturnType(handle.invoke(args));
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method)
|
||||
|
@ -360,7 +357,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialStringMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -370,7 +367,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -380,7 +377,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -423,7 +420,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
objectType = decoder.objectType;
|
||||
}
|
||||
MethodHandle methodHandle = getMethodHandle.apply(getArgsFor(objectType));
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
|
||||
// Set the sinkClass and then set the MessageMetadata on the FrameHandlerMetadata
|
||||
if (interfaceType.equals(Decoder.Text.class))
|
||||
|
@ -508,7 +505,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
* have been statically assigned a converted value (and removed from the resulting {@link MethodHandle#type()}, or null if
|
||||
* no {@code target} MethodHandle was provided.
|
||||
*/
|
||||
public static MethodHandle bindTemplateVariables(MethodHandle target, String[] namedVariables, Map<String, String> templateValues)
|
||||
public static MethodHolder bindTemplateVariables(MethodHolder target, String[] namedVariables, Map<String, String> templateValues)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
|
@ -517,7 +514,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
|
||||
final int IDX = 1;
|
||||
|
||||
MethodHandle retHandle = target;
|
||||
MethodHolder retHandle = target;
|
||||
|
||||
if ((templateValues == null) || (templateValues.isEmpty()))
|
||||
{
|
||||
|
@ -527,54 +524,54 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
for (String variableName : namedVariables)
|
||||
{
|
||||
String strValue = templateValues.get(variableName);
|
||||
Class<?> type = retHandle.type().parameterType(IDX);
|
||||
Class<?> type = retHandle.parameterType(IDX);
|
||||
try
|
||||
{
|
||||
if (String.class.isAssignableFrom(type))
|
||||
{
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, strValue);
|
||||
retHandle = retHandle.bindTo(strValue, IDX);
|
||||
}
|
||||
else if (Integer.class.isAssignableFrom(type) || Integer.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Integer intValue = Integer.parseInt(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, intValue);
|
||||
retHandle = retHandle.bindTo(intValue, IDX);
|
||||
}
|
||||
else if (Long.class.isAssignableFrom(type) || Long.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Long longValue = Long.parseLong(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, longValue);
|
||||
retHandle = retHandle.bindTo(longValue, IDX);
|
||||
}
|
||||
else if (Short.class.isAssignableFrom(type) || Short.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Short shortValue = Short.parseShort(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, shortValue);
|
||||
retHandle = retHandle.bindTo(shortValue, IDX);
|
||||
}
|
||||
else if (Float.class.isAssignableFrom(type) || Float.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Float floatValue = Float.parseFloat(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, floatValue);
|
||||
retHandle = retHandle.bindTo(floatValue, IDX);
|
||||
}
|
||||
else if (Double.class.isAssignableFrom(type) || Double.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Double doubleValue = Double.parseDouble(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, doubleValue);
|
||||
retHandle = retHandle.bindTo(doubleValue, IDX);
|
||||
}
|
||||
else if (Boolean.class.isAssignableFrom(type) || Boolean.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Boolean boolValue = Boolean.parseBoolean(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, boolValue);
|
||||
retHandle = retHandle.bindTo(boolValue, IDX);
|
||||
}
|
||||
else if (Character.class.isAssignableFrom(type) || Character.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
if (strValue.length() != 1)
|
||||
throw new IllegalArgumentException("Invalid Size");
|
||||
Character charValue = strValue.charAt(0);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, charValue);
|
||||
retHandle = retHandle.bindTo(charValue, IDX);
|
||||
}
|
||||
else if (Byte.class.isAssignableFrom(type) || Byte.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Byte b = Byte.parseByte(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, b);
|
||||
retHandle = retHandle.bindTo(b, IDX);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -13,15 +13,15 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class JakartaWebSocketMessageMetadata
|
||||
{
|
||||
private MethodHandle methodHandle;
|
||||
private MethodHolder methodHolder;
|
||||
private Class<? extends MessageSink> sinkClass;
|
||||
private List<RegisteredDecoder> registeredDecoders;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class JakartaWebSocketMessageMetadata
|
|||
return null;
|
||||
|
||||
JakartaWebSocketMessageMetadata copy = new JakartaWebSocketMessageMetadata();
|
||||
copy.methodHandle = metadata.methodHandle;
|
||||
copy.methodHolder = metadata.methodHolder;
|
||||
copy.sinkClass = metadata.sinkClass;
|
||||
copy.registeredDecoders = metadata.registeredDecoders;
|
||||
copy.maxMessageSize = metadata.maxMessageSize;
|
||||
|
@ -58,14 +58,14 @@ public class JakartaWebSocketMessageMetadata
|
|||
this.maxMessageSizeSet = true;
|
||||
}
|
||||
|
||||
public MethodHandle getMethodHandle()
|
||||
public MethodHolder getMethodHolder()
|
||||
{
|
||||
return methodHandle;
|
||||
return methodHolder;
|
||||
}
|
||||
|
||||
public void setMethodHandle(MethodHandle methodHandle)
|
||||
public void setMethodHolder(MethodHolder methodHandle)
|
||||
{
|
||||
this.methodHandle = methodHandle;
|
||||
this.methodHolder = methodHandle;
|
||||
}
|
||||
|
||||
public Class<? extends MessageSink> getSinkClass()
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -25,6 +24,7 @@ import org.eclipse.jetty.websocket.core.CoreSession;
|
|||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -32,12 +32,12 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractDecodedMessageSink.class);
|
||||
|
||||
private final MethodHandle _methodHandle;
|
||||
private final MethodHolder _methodHolder;
|
||||
private final MessageSink _messageSink;
|
||||
|
||||
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHandle methodHandle)
|
||||
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHolder methodHolder)
|
||||
{
|
||||
_methodHandle = methodHandle;
|
||||
_methodHolder = methodHolder;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
try
|
||||
{
|
||||
_methodHandle.invoke(message);
|
||||
_methodHolder.invoke(message);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
}
|
||||
|
||||
/**
|
||||
* @return a message sink which will first decode the message then pass it to {@link #_methodHandle}.
|
||||
* @return a message sink which will first decode the message then pass it to {@link #_methodHolder}.
|
||||
* @throws Exception for any error in creating the message sink.
|
||||
*/
|
||||
abstract MessageSink newMessageSink(CoreSession coreSession) throws Exception;
|
||||
|
@ -90,9 +90,9 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
protected final List<T> _decoders;
|
||||
|
||||
public Basic(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public Basic(CoreSession coreSession, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(coreSession, methodHandle);
|
||||
super(coreSession, methodHolder);
|
||||
if (decoders.isEmpty())
|
||||
throw new IllegalArgumentException("Require at least one decoder for " + this.getClass());
|
||||
_decoders = decoders.stream()
|
||||
|
@ -105,9 +105,9 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
protected final T _decoder;
|
||||
|
||||
public Stream(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public Stream(CoreSession coreSession, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(coreSession, methodHandle);
|
||||
super(coreSession, methodHolder);
|
||||
if (decoders.size() != 1)
|
||||
throw new IllegalArgumentException("Require exactly one decoder for " + this.getClass());
|
||||
_decoder = decoders.get(0).getInstance();
|
||||
|
|
|
@ -13,20 +13,19 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.ByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -34,18 +33,23 @@ public class DecodedBinaryMessageSink<T> extends AbstractDecodedMessageSink.Basi
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DecodedBinaryMessageSink.class);
|
||||
|
||||
public DecodedBinaryMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedBinaryMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedBinaryMessageSink.class, "onWholeMessage", MethodType.methodType(void.class, ByteBuffer.class))
|
||||
.bindTo(this);
|
||||
return new ByteBufferMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onWholeMessage((ByteBuffer)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new ByteBufferMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onWholeMessage(ByteBuffer wholeMessage)
|
||||
|
|
|
@ -15,34 +15,38 @@ package org.eclipse.jetty.ee10.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class DecodedBinaryStreamMessageSink<T> extends AbstractDecodedMessageSink.Stream<Decoder.BinaryStream<T>>
|
||||
{
|
||||
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedBinaryStreamMessageSink.class, "onStreamStart", MethodType.methodType(void.class, InputStream.class))
|
||||
.bindTo(this);
|
||||
return new InputStreamMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onStreamStart((InputStream)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new InputStreamMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onStreamStart(InputStream stream)
|
||||
|
|
|
@ -13,19 +13,18 @@
|
|||
|
||||
package org.eclipse.jetty.ee10.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -33,18 +32,23 @@ public class DecodedTextMessageSink<T> extends AbstractDecodedMessageSink.Basic<
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DecodedTextMessageSink.class);
|
||||
|
||||
public DecodedTextMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedTextMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws NoSuchMethodException, IllegalAccessException
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(getClass(), "onMessage", MethodType.methodType(void.class, String.class))
|
||||
.bindTo(this);
|
||||
return new StringMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onMessage((String)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new StringMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onMessage(String wholeMessage)
|
||||
|
|
|
@ -15,34 +15,38 @@ package org.eclipse.jetty.ee10.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class DecodedTextStreamMessageSink<T> extends AbstractDecodedMessageSink.Stream<Decoder.TextStream<T>>
|
||||
{
|
||||
public DecodedTextStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedTextStreamMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedTextStreamMessageSink.class, "onStreamStart", MethodType.methodType(void.class, Reader.class))
|
||||
.bindTo(this);
|
||||
return new ReaderMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onStreamStart((Reader)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new ReaderMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onStreamStart(Reader reader)
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecode
|
|||
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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -46,7 +47,7 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
ByteBuffer data = ByteBuffer.allocate(16);
|
||||
|
@ -69,7 +70,7 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -49,7 +50,7 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
ByteBuffer data = ByteBuffer.allocate(16);
|
||||
|
@ -72,7 +73,7 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.ee10.websocket.jakarta.common.decoders.RegisteredDecode
|
|||
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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -47,7 +48,7 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
|
||||
|
@ -65,7 +66,7 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
|
|
@ -34,6 +34,7 @@ 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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -50,7 +51,7 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
sink.accept(new Frame(OpCode.TEXT).setPayload("2018.02.13").setFin(true), finCallback);
|
||||
|
@ -68,7 +69,7 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(copyHandle), decoders);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
|
|
@ -32,6 +32,7 @@ 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.core.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
@ -46,7 +47,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), MethodHolder.from(copyHandle), true);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
ByteBuffer data = BufferUtil.toBuffer("Hello World", UTF_8);
|
||||
|
@ -64,7 +65,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), MethodHolder.from(copyHandle), true);
|
||||
|
||||
FutureCallback fin1Callback = new FutureCallback();
|
||||
ByteBuffer data1 = BufferUtil.toBuffer("Hello World", UTF_8);
|
||||
|
@ -95,7 +96,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), MethodHolder.from(copyHandle), true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
@ -120,7 +121,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), MethodHolder.from(copyHandle), true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
|
|
@ -28,6 +28,7 @@ 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.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -41,7 +42,7 @@ 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.getCoreSession(), copyHandle, true);
|
||||
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), MethodHolder.from(copyHandle), true);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
sink.accept(new Frame(OpCode.TEXT).setPayload("Hello World"), finCallback);
|
||||
|
@ -58,7 +59,7 @@ 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.getCoreSession(), copyHandle, true);
|
||||
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), MethodHolder.from(copyHandle), true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
FutureCallback callback2 = new FutureCallback();
|
||||
|
|
|
@ -23,6 +23,7 @@ import jakarta.websocket.Session;
|
|||
import org.eclipse.jetty.ee10.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -57,6 +58,12 @@ public class InvokerUtilsStaticParamsTest
|
|||
|
||||
private static MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
private MethodHolder getMethodHolder(Method method, String[] namedVariables, InvokerUtils.Arg... args)
|
||||
{
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, args);
|
||||
return MethodHolder.from(methodHandle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyParamString() throws Throwable
|
||||
{
|
||||
|
@ -70,21 +77,21 @@ 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(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("fruit", "pear");
|
||||
|
||||
// Bind the static values, in same order as declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke();
|
||||
String result = (String)methodHolder.invoke();
|
||||
assertThat("Result", result, is("onFruit('pear')"));
|
||||
}
|
||||
|
||||
|
@ -99,21 +106,21 @@ public class InvokerUtilsStaticParamsTest
|
|||
};
|
||||
|
||||
// Get basic method handle (without a instance to call against) - this is what the metadata stores
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("count", "2222");
|
||||
|
||||
// Bind the static values for the variables, in same order as the variables were declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke();
|
||||
String result = (String)methodHolder.invoke();
|
||||
assertThat("Result", result, is("onCount(2222)"));
|
||||
}
|
||||
|
||||
|
@ -130,21 +137,21 @@ public class InvokerUtilsStaticParamsTest
|
|||
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(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, ARG_LABEL);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables, ARG_LABEL);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("count", "444");
|
||||
|
||||
// Bind the static values for the variables, in same order as the variables were declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke("cherry");
|
||||
String result = (String)methodHolder.invoke("cherry");
|
||||
assertThat("Result", result, is("onLabeledCount('cherry', 444)"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -80,7 +81,7 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
|||
});
|
||||
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(QuotesDecoder.class, Quotes.class);
|
||||
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), quoteHandle, decoders);
|
||||
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(quoteHandle), decoders);
|
||||
|
||||
List<FutureCallback> callbacks = new ArrayList<>();
|
||||
FutureCallback finCallback = null;
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.ee11.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
class JakartaMessagePartialMethodHolder<T> implements MethodHolder
|
||||
{
|
||||
private final MessageHandler.Partial<T> _messageHandler;
|
||||
|
||||
public JakartaMessagePartialMethodHolder(MessageHandler.Partial<T> messageHandler)
|
||||
{
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
if (args.length != 2)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 2, args.length));
|
||||
_messageHandler.onMessage((T)args[0], (boolean)args[1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return Object.class;
|
||||
case 1:
|
||||
return boolean.class;
|
||||
default:
|
||||
throw new IndexOutOfBoundsException(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return void.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.ee11.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
class JakartaMessageWholeMethodHolder<T> implements MethodHolder
|
||||
{
|
||||
private final MessageHandler.Whole<T> _messageHandler;
|
||||
|
||||
public JakartaMessageWholeMethodHolder(MessageHandler.Whole<T> messageHandler)
|
||||
{
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
_messageHandler.onMessage((T)args[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return Object.class;
|
||||
default:
|
||||
throw new IndexOutOfBoundsException(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return void.class;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -51,6 +49,7 @@ import org.eclipse.jetty.websocket.core.messages.PartialByteArrayMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -62,10 +61,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
private final Object endpointInstance;
|
||||
private final AtomicBoolean closeNotified = new AtomicBoolean();
|
||||
|
||||
private MethodHandle openHandle;
|
||||
private MethodHandle closeHandle;
|
||||
private MethodHandle errorHandle;
|
||||
private MethodHandle pongHandle;
|
||||
private MethodHolder openHandle;
|
||||
private MethodHolder closeHandle;
|
||||
private MethodHolder errorHandle;
|
||||
private MethodHolder pongHandle;
|
||||
private JakartaWebSocketMessageMetadata textMetadata;
|
||||
private JakartaWebSocketMessageMetadata binaryMetadata;
|
||||
private final UpgradeRequest upgradeRequest;
|
||||
|
@ -79,12 +78,12 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
protected byte dataType = OpCode.UNDEFINED;
|
||||
|
||||
public JakartaWebSocketFrameHandler(JakartaWebSocketContainer container,
|
||||
UpgradeRequest upgradeRequest,
|
||||
UpgradeRequest upgradeRequest,
|
||||
Object endpointInstance,
|
||||
MethodHandle openHandle, MethodHandle closeHandle, MethodHandle errorHandle,
|
||||
JakartaWebSocketMessageMetadata textMetadata,
|
||||
JakartaWebSocketMessageMetadata binaryMetadata,
|
||||
MethodHandle pongHandle,
|
||||
MethodHolder openHandle, MethodHolder closeHandle, MethodHolder errorHandle,
|
||||
JakartaWebSocketMessageMetadata textMetadata,
|
||||
JakartaWebSocketMessageMetadata binaryMetadata,
|
||||
MethodHolder pongHandle,
|
||||
EndpointConfig endpointConfig)
|
||||
{
|
||||
this.logger = LoggerFactory.getLogger(endpointInstance.getClass());
|
||||
|
@ -147,10 +146,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
if (actualTextMetadata.isMaxMessageSizeSet())
|
||||
session.setMaxTextMessageBufferSize(actualTextMetadata.getMaxMessageSize());
|
||||
|
||||
MethodHandle methodHandle = actualTextMetadata.getMethodHandle();
|
||||
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||
actualTextMetadata.setMethodHandle(methodHandle);
|
||||
MethodHolder methodHolder = actualTextMetadata.getMethodHolder();
|
||||
methodHolder = InvokerUtils.bindTo(methodHolder, endpointInstance, endpointConfig, session);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHolder, session);
|
||||
actualTextMetadata.setMethodHolder(methodHolder);
|
||||
|
||||
textSink = JakartaWebSocketFrameHandlerFactory.createMessageSink(session, actualTextMetadata);
|
||||
textMetadata = actualTextMetadata;
|
||||
|
@ -162,10 +161,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
if (actualBinaryMetadata.isMaxMessageSizeSet())
|
||||
session.setMaxBinaryMessageBufferSize(actualBinaryMetadata.getMaxMessageSize());
|
||||
|
||||
MethodHandle methodHandle = actualBinaryMetadata.getMethodHandle();
|
||||
MethodHolder methodHandle = actualBinaryMetadata.getMethodHolder();
|
||||
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||
actualBinaryMetadata.setMethodHandle(methodHandle);
|
||||
actualBinaryMetadata.setMethodHolder(methodHandle);
|
||||
|
||||
binarySink = JakartaWebSocketFrameHandlerFactory.createMessageSink(session, actualBinaryMetadata);
|
||||
binaryMetadata = actualBinaryMetadata;
|
||||
|
@ -346,116 +345,88 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
|
||||
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
|
||||
{
|
||||
try
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHolder(new JakartaMessagePartialMethodHolder<>(handler));
|
||||
byte basicType;
|
||||
// MessageHandler.Partial has no decoder support!
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(MessageHandler.Partial.class, "onMessage", MethodType.methodType(void.class, Object.class, boolean.class))
|
||||
.bindTo(handler);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
}
|
||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
}
|
||||
else if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Unable to add " + handler.getClass().getName() + " with type " + clazz + ": only supported types byte[], " + ByteBuffer.class.getName() +
|
||||
", " + String.class.getName());
|
||||
}
|
||||
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHandle(methodHandle);
|
||||
byte basicType;
|
||||
// MessageHandler.Partial has no decoder support!
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
}
|
||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
}
|
||||
else if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Unable to add " + handler.getClass().getName() + " with type " + clazz + ": only supported types byte[], " + ByteBuffer.class.getName() +
|
||||
", " + String.class.getName());
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to find method", e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to access " + handler.getClass().getName(), e);
|
||||
}
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
|
||||
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
|
||||
{
|
||||
try
|
||||
MethodHolder methodHolder = new JakartaMessageWholeMethodHolder<>(handler);
|
||||
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class))
|
||||
.bindTo(handler);
|
||||
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
assertBasicTypeNotRegistered(OpCode.PONG, handler);
|
||||
this.pongHandle = methodHandle;
|
||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||
return;
|
||||
}
|
||||
|
||||
AvailableDecoders availableDecoders = session.getDecoders();
|
||||
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||
if (registeredDecoder == null)
|
||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||
|
||||
// Create the message metadata specific to the MessageHandler type.
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHandle(methodHandle);
|
||||
byte basicType;
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Unable to add " + handler.getClass().getName() + ": type " + clazz + " is unrecognized by declared decoders");
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
assertBasicTypeNotRegistered(OpCode.PONG, handler);
|
||||
this.pongHandle = methodHolder;
|
||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||
return;
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
||||
AvailableDecoders availableDecoders = session.getDecoders();
|
||||
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||
if (registeredDecoder == null)
|
||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||
|
||||
// Create the message metadata specific to the MessageHandler type.
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHolder(methodHolder);
|
||||
byte basicType;
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
throw new IllegalStateException("Unable to find method", e);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
throw new IllegalStateException("Unable to access " + handler.getClass().getName(), e);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Unable to add " + handler.getClass().getName() + ": type " + clazz + " is unrecognized by declared decoders");
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
|
||||
private void assertBasicTypeNotRegistered(byte basicWebSocketType, MessageHandler replacement)
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.eclipse.jetty.websocket.core.messages.PartialByteArrayMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
|
||||
public abstract class JakartaWebSocketFrameHandlerFactory
|
||||
|
@ -135,10 +136,10 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (metadata == null)
|
||||
return null;
|
||||
|
||||
MethodHandle openHandle = metadata.getOpenHandle();
|
||||
MethodHandle closeHandle = metadata.getCloseHandle();
|
||||
MethodHandle errorHandle = metadata.getErrorHandle();
|
||||
MethodHandle pongHandle = metadata.getPongHandle();
|
||||
MethodHolder openHandle = MethodHolder.from(metadata.getOpenHandle());
|
||||
MethodHolder closeHandle = MethodHolder.from(metadata.getCloseHandle());
|
||||
MethodHolder errorHandle = MethodHolder.from(metadata.getErrorHandle());
|
||||
MethodHolder pongHandle = MethodHolder.from(metadata.getPongHandle());
|
||||
|
||||
JakartaWebSocketMessageMetadata textMetadata = JakartaWebSocketMessageMetadata.copyOf(metadata.getTextMetadata());
|
||||
JakartaWebSocketMessageMetadata binaryMetadata = JakartaWebSocketMessageMetadata.copyOf(metadata.getBinaryMetadata());
|
||||
|
@ -156,9 +157,9 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
pongHandle = bindTemplateVariables(pongHandle, namedVariables, pathParams);
|
||||
|
||||
if (textMetadata != null)
|
||||
textMetadata.setMethodHandle(bindTemplateVariables(textMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||
textMetadata.setMethodHolder(bindTemplateVariables(textMetadata.getMethodHolder(), namedVariables, pathParams));
|
||||
if (binaryMetadata != null)
|
||||
binaryMetadata.setMethodHandle(bindTemplateVariables(binaryMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||
binaryMetadata.setMethodHolder(bindTemplateVariables(binaryMetadata.getMethodHolder(), namedVariables, pathParams));
|
||||
}
|
||||
|
||||
openHandle = InvokerUtils.bindTo(openHandle, endpoint);
|
||||
|
@ -190,15 +191,15 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (AbstractDecodedMessageSink.class.isAssignableFrom(msgMetadata.getSinkClass()))
|
||||
{
|
||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, List.class));
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, List.class));
|
||||
List<RegisteredDecoder> registeredDecoders = msgMetadata.getRegisteredDecoders();
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), registeredDecoders);
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHolder(), registeredDecoders);
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), true);
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHolder(), true);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
@ -219,23 +220,19 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
}
|
||||
}
|
||||
|
||||
public static MethodHandle wrapNonVoidReturnType(MethodHandle handle, JakartaWebSocketSession session)
|
||||
public static MethodHolder wrapNonVoidReturnType(MethodHolder holder, JakartaWebSocketSession session)
|
||||
{
|
||||
if (handle == null)
|
||||
if (holder == null)
|
||||
return null;
|
||||
|
||||
if (handle.type().returnType() == Void.TYPE)
|
||||
return handle;
|
||||
if (holder.returnType() == Void.TYPE)
|
||||
return holder;
|
||||
|
||||
// Technique from https://stackoverflow.com/questions/48505787/methodhandle-with-general-non-void-return-filter
|
||||
|
||||
// Change the return type of the to be Object so it will match exact with JakartaWebSocketSession.filterReturnType(Object)
|
||||
handle = handle.asType(handle.type().changeReturnType(Object.class));
|
||||
|
||||
// Filter the method return type to a call to JakartaWebSocketSession.filterReturnType() bound to this session
|
||||
handle = MethodHandles.filterReturnValue(handle, FILTER_RETURN_TYPE_METHOD.bindTo(session));
|
||||
|
||||
return handle;
|
||||
return args ->
|
||||
{
|
||||
session.filterReturnType(holder.invoke(args));
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method)
|
||||
|
@ -360,7 +357,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialStringMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -370,7 +367,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -380,7 +377,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -423,7 +420,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
objectType = decoder.objectType;
|
||||
}
|
||||
MethodHandle methodHandle = getMethodHandle.apply(getArgsFor(objectType));
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
|
||||
// Set the sinkClass and then set the MessageMetadata on the FrameHandlerMetadata
|
||||
if (interfaceType.equals(Decoder.Text.class))
|
||||
|
@ -508,7 +505,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
* have been statically assigned a converted value (and removed from the resulting {@link MethodHandle#type()}, or null if
|
||||
* no {@code target} MethodHandle was provided.
|
||||
*/
|
||||
public static MethodHandle bindTemplateVariables(MethodHandle target, String[] namedVariables, Map<String, String> templateValues)
|
||||
public static MethodHolder bindTemplateVariables(MethodHolder target, String[] namedVariables, Map<String, String> templateValues)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
|
@ -517,7 +514,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
|
||||
final int IDX = 1;
|
||||
|
||||
MethodHandle retHandle = target;
|
||||
MethodHolder retHandle = target;
|
||||
|
||||
if ((templateValues == null) || (templateValues.isEmpty()))
|
||||
{
|
||||
|
@ -527,54 +524,58 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
for (String variableName : namedVariables)
|
||||
{
|
||||
String strValue = templateValues.get(variableName);
|
||||
Class<?> type = retHandle.type().parameterType(IDX);
|
||||
Class<?> type = retHandle.parameterType(IDX);
|
||||
try
|
||||
{
|
||||
if (String.class.isAssignableFrom(type))
|
||||
{
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, strValue);
|
||||
retHandle = retHandle.bindTo(strValue, IDX);
|
||||
}
|
||||
else if (Integer.class.isAssignableFrom(type) || Integer.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Integer intValue = Integer.parseInt(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, intValue);
|
||||
retHandle = retHandle.bindTo(intValue, IDX);
|
||||
}
|
||||
else if (Long.class.isAssignableFrom(type) || Long.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Long longValue = Long.parseLong(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, longValue);
|
||||
retHandle = retHandle.bindTo(longValue, IDX);
|
||||
}
|
||||
else if (Short.class.isAssignableFrom(type) || Short.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Short shortValue = Short.parseShort(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, shortValue);
|
||||
retHandle = retHandle.bindTo(shortValue, IDX);
|
||||
|
||||
}
|
||||
else if (Float.class.isAssignableFrom(type) || Float.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Float floatValue = Float.parseFloat(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, floatValue);
|
||||
retHandle = retHandle.bindTo(floatValue, IDX);
|
||||
|
||||
}
|
||||
else if (Double.class.isAssignableFrom(type) || Double.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Double doubleValue = Double.parseDouble(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, doubleValue);
|
||||
retHandle = retHandle.bindTo(doubleValue, IDX);
|
||||
|
||||
}
|
||||
else if (Boolean.class.isAssignableFrom(type) || Boolean.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Boolean boolValue = Boolean.parseBoolean(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, boolValue);
|
||||
retHandle = retHandle.bindTo(boolValue, IDX);
|
||||
|
||||
}
|
||||
else if (Character.class.isAssignableFrom(type) || Character.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
if (strValue.length() != 1)
|
||||
throw new IllegalArgumentException("Invalid Size");
|
||||
Character charValue = strValue.charAt(0);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, charValue);
|
||||
retHandle = retHandle.bindTo(charValue, IDX);
|
||||
}
|
||||
else if (Byte.class.isAssignableFrom(type) || Byte.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Byte b = Byte.parseByte(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, b);
|
||||
retHandle = retHandle.bindTo(b, IDX);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -13,15 +13,15 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class JakartaWebSocketMessageMetadata
|
||||
{
|
||||
private MethodHandle methodHandle;
|
||||
private MethodHolder methodHolder;
|
||||
private Class<? extends MessageSink> sinkClass;
|
||||
private List<RegisteredDecoder> registeredDecoders;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class JakartaWebSocketMessageMetadata
|
|||
return null;
|
||||
|
||||
JakartaWebSocketMessageMetadata copy = new JakartaWebSocketMessageMetadata();
|
||||
copy.methodHandle = metadata.methodHandle;
|
||||
copy.methodHolder = metadata.methodHolder;
|
||||
copy.sinkClass = metadata.sinkClass;
|
||||
copy.registeredDecoders = metadata.registeredDecoders;
|
||||
copy.maxMessageSize = metadata.maxMessageSize;
|
||||
|
@ -58,14 +58,14 @@ public class JakartaWebSocketMessageMetadata
|
|||
this.maxMessageSizeSet = true;
|
||||
}
|
||||
|
||||
public MethodHandle getMethodHandle()
|
||||
public MethodHolder getMethodHolder()
|
||||
{
|
||||
return methodHandle;
|
||||
return methodHolder;
|
||||
}
|
||||
|
||||
public void setMethodHandle(MethodHandle methodHandle)
|
||||
public void setMethodHolder(MethodHolder methodHolder)
|
||||
{
|
||||
this.methodHandle = methodHandle;
|
||||
this.methodHolder = methodHolder;
|
||||
}
|
||||
|
||||
public Class<? extends MessageSink> getSinkClass()
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -25,6 +24,7 @@ import org.eclipse.jetty.websocket.core.CoreSession;
|
|||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -32,12 +32,12 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractDecodedMessageSink.class);
|
||||
|
||||
private final MethodHandle _methodHandle;
|
||||
private final MethodHolder _methodHolder;
|
||||
private final MessageSink _messageSink;
|
||||
|
||||
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHandle methodHandle)
|
||||
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHolder methodHolder)
|
||||
{
|
||||
_methodHandle = methodHandle;
|
||||
_methodHolder = methodHolder;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
try
|
||||
{
|
||||
_methodHandle.invoke(message);
|
||||
_methodHolder.invoke(message);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
}
|
||||
|
||||
/**
|
||||
* @return a message sink which will first decode the message then pass it to {@link #_methodHandle}.
|
||||
* @return a message sink which will first decode the message then pass it to {@link #_methodHolder}.
|
||||
* @throws Exception for any error in creating the message sink.
|
||||
*/
|
||||
abstract MessageSink newMessageSink(CoreSession coreSession) throws Exception;
|
||||
|
@ -90,9 +90,9 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
protected final List<T> _decoders;
|
||||
|
||||
public Basic(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public Basic(CoreSession coreSession, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(coreSession, methodHandle);
|
||||
super(coreSession, methodHolder);
|
||||
if (decoders.isEmpty())
|
||||
throw new IllegalArgumentException("Require at least one decoder for " + this.getClass());
|
||||
_decoders = decoders.stream()
|
||||
|
@ -105,9 +105,9 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
protected final T _decoder;
|
||||
|
||||
public Stream(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public Stream(CoreSession coreSession, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(coreSession, methodHandle);
|
||||
super(coreSession, methodHolder);
|
||||
if (decoders.size() != 1)
|
||||
throw new IllegalArgumentException("Require exactly one decoder for " + this.getClass());
|
||||
_decoder = decoders.get(0).getInstance();
|
||||
|
|
|
@ -13,20 +13,19 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.ByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -34,18 +33,23 @@ public class DecodedBinaryMessageSink<T> extends AbstractDecodedMessageSink.Basi
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DecodedBinaryMessageSink.class);
|
||||
|
||||
public DecodedBinaryMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedBinaryMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedBinaryMessageSink.class, "onWholeMessage", MethodType.methodType(void.class, ByteBuffer.class))
|
||||
.bindTo(this);
|
||||
return new ByteBufferMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onWholeMessage((ByteBuffer)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new ByteBufferMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onWholeMessage(ByteBuffer wholeMessage)
|
||||
|
|
|
@ -15,34 +15,38 @@ package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class DecodedBinaryStreamMessageSink<T> extends AbstractDecodedMessageSink.Stream<Decoder.BinaryStream<T>>
|
||||
{
|
||||
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedBinaryStreamMessageSink.class, "onStreamStart", MethodType.methodType(void.class, InputStream.class))
|
||||
.bindTo(this);
|
||||
return new InputStreamMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onStreamStart((InputStream)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new InputStreamMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onStreamStart(InputStream stream)
|
||||
|
|
|
@ -13,19 +13,18 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -33,18 +32,23 @@ public class DecodedTextMessageSink<T> extends AbstractDecodedMessageSink.Basic<
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DecodedTextMessageSink.class);
|
||||
|
||||
public DecodedTextMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedTextMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws NoSuchMethodException, IllegalAccessException
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(getClass(), "onMessage", MethodType.methodType(void.class, String.class))
|
||||
.bindTo(this);
|
||||
return new StringMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onMessage((String)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new StringMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onMessage(String wholeMessage)
|
||||
|
|
|
@ -15,34 +15,38 @@ package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class DecodedTextStreamMessageSink<T> extends AbstractDecodedMessageSink.Stream<Decoder.TextStream<T>>
|
||||
{
|
||||
public DecodedTextStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedTextStreamMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedTextStreamMessageSink.class, "onStreamStart", MethodType.methodType(void.class, Reader.class))
|
||||
.bindTo(this);
|
||||
return new ReaderMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onStreamStart((Reader)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new ReaderMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onStreamStart(Reader reader)
|
||||
|
|
|
@ -23,6 +23,7 @@ import jakarta.websocket.Decoder;
|
|||
import org.eclipse.jetty.ee11.websocket.jakarta.common.AbstractSessionTest;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
||||
{
|
||||
|
@ -43,7 +44,7 @@ public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
|||
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build(), components));
|
||||
}
|
||||
|
||||
public <T> MethodHandle getAcceptHandle(Consumer<T> copy, Class<T> type)
|
||||
public <T> MethodHolder getAcceptHandle(Consumer<T> copy, Class<T> type)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -51,7 +52,7 @@ public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
|||
String name = "accept";
|
||||
MethodType methodType = MethodType.methodType(void.class, type);
|
||||
MethodHandle handle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(refc, name, methodType);
|
||||
return handle.bindTo(copy);
|
||||
return MethodHolder.from(handle.bindTo(copy));
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException e)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -30,6 +29,7 @@ import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecode
|
|||
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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -44,7 +44,7 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -67,7 +67,7 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -33,6 +32,7 @@ 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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -47,7 +47,7 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -70,7 +70,7 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -31,6 +30,7 @@ import org.eclipse.jetty.ee11.websocket.jakarta.common.decoders.RegisteredDecode
|
|||
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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -45,7 +45,7 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -63,7 +63,7 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -34,6 +33,7 @@ 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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -48,7 +48,7 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -66,7 +66,7 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -32,6 +31,7 @@ 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.core.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
@ -45,7 +45,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream1Message1Frame() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
|
@ -63,7 +63,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream2Messages2Frames() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback fin1Callback = new FutureCallback();
|
||||
|
@ -94,7 +94,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream1Message3Frames() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
|
@ -119,7 +119,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream1Message4FramesEmptyFin() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
|
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.ee11.websocket.jakarta.common.messages;
|
|||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -28,6 +27,7 @@ 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.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -40,7 +40,7 @@ public class ReaderMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<StringWriter> copyFuture = new CompletableFuture<>();
|
||||
ReaderCopy copy = new ReaderCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
|
@ -57,7 +57,7 @@ public class ReaderMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<StringWriter> copyFuture = new CompletableFuture<>();
|
||||
ReaderCopy copy = new ReaderCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
|
|
|
@ -23,6 +23,7 @@ import jakarta.websocket.Session;
|
|||
import org.eclipse.jetty.ee11.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -57,6 +58,12 @@ public class InvokerUtilsStaticParamsTest
|
|||
|
||||
private static MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
private MethodHolder getMethodHolder(Method method, String[] namedVariables, InvokerUtils.Arg... args)
|
||||
{
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, args);
|
||||
return MethodHolder.from(methodHandle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyParamString() throws Throwable
|
||||
{
|
||||
|
@ -70,21 +77,20 @@ 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(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("fruit", "pear");
|
||||
|
||||
// Bind the static values, in same order as declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke();
|
||||
String result = (String)methodHolder.invoke();
|
||||
assertThat("Result", result, is("onFruit('pear')"));
|
||||
}
|
||||
|
||||
|
@ -99,21 +105,21 @@ public class InvokerUtilsStaticParamsTest
|
|||
};
|
||||
|
||||
// Get basic method handle (without a instance to call against) - this is what the metadata stores
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("count", "2222");
|
||||
|
||||
// Bind the static values for the variables, in same order as the variables were declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke();
|
||||
String result = (String)methodHolder.invoke();
|
||||
assertThat("Result", result, is("onCount(2222)"));
|
||||
}
|
||||
|
||||
|
@ -130,21 +136,21 @@ public class InvokerUtilsStaticParamsTest
|
|||
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(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, ARG_LABEL);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables, ARG_LABEL);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("count", "444");
|
||||
|
||||
// Bind the static values for the variables, in same order as the variables were declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke("cherry");
|
||||
String result = (String)methodHolder.invoke("cherry");
|
||||
assertThat("Result", result, is("onLabeledCount('cherry', 444)"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -80,7 +81,7 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
|||
});
|
||||
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(QuotesDecoder.class, Quotes.class);
|
||||
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), quoteHandle, decoders);
|
||||
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(quoteHandle), decoders);
|
||||
|
||||
List<FutureCallback> callbacks = new ArrayList<>();
|
||||
FutureCallback finCallback = null;
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.ee9.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
class JakartaMessagePartialMethodHolder<T> implements MethodHolder
|
||||
{
|
||||
private final MessageHandler.Partial<T> _messageHandler;
|
||||
|
||||
public JakartaMessagePartialMethodHolder(MessageHandler.Partial<T> messageHandler)
|
||||
{
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
if (args.length != 2)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 2, args.length));
|
||||
_messageHandler.onMessage((T)args[0], (boolean)args[1]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return Object.class;
|
||||
case 1:
|
||||
return boolean.class;
|
||||
default:
|
||||
throw new IndexOutOfBoundsException(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return void.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.ee9.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
import jakarta.websocket.MessageHandler;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
class JakartaMessageWholeMethodHolder<T> implements MethodHolder
|
||||
{
|
||||
private final MessageHandler.Whole<T> _messageHandler;
|
||||
|
||||
public JakartaMessageWholeMethodHolder(MessageHandler.Whole<T> messageHandler)
|
||||
{
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object invoke(Object... args) throws Throwable
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
_messageHandler.onMessage((T)args[0]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> parameterType(int idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return Object.class;
|
||||
default:
|
||||
throw new IndexOutOfBoundsException(idx);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> returnType()
|
||||
{
|
||||
return void.class;
|
||||
}
|
||||
}
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -52,6 +50,7 @@ import org.eclipse.jetty.websocket.core.messages.PartialByteArrayMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -63,10 +62,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
private final Object endpointInstance;
|
||||
private final AtomicBoolean closeNotified = new AtomicBoolean();
|
||||
|
||||
private MethodHandle openHandle;
|
||||
private MethodHandle closeHandle;
|
||||
private MethodHandle errorHandle;
|
||||
private MethodHandle pongHandle;
|
||||
private MethodHolder openHandle;
|
||||
private MethodHolder closeHandle;
|
||||
private MethodHolder errorHandle;
|
||||
private MethodHolder pongHandle;
|
||||
private JakartaWebSocketMessageMetadata textMetadata;
|
||||
private JakartaWebSocketMessageMetadata binaryMetadata;
|
||||
private final UpgradeRequest upgradeRequest;
|
||||
|
@ -81,12 +80,12 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
|
||||
public JakartaWebSocketFrameHandler(JakartaWebSocketContainer container,
|
||||
UpgradeRequest upgradeRequest,
|
||||
Object endpointInstance,
|
||||
MethodHandle openHandle, MethodHandle closeHandle, MethodHandle errorHandle,
|
||||
Object endpointInstance,
|
||||
MethodHolder openHandle, MethodHolder closeHandle, MethodHolder errorHandle,
|
||||
JakartaWebSocketMessageMetadata textMetadata,
|
||||
JakartaWebSocketMessageMetadata binaryMetadata,
|
||||
MethodHandle pongHandle,
|
||||
EndpointConfig endpointConfig)
|
||||
MethodHolder pongHandle,
|
||||
EndpointConfig endpointConfig)
|
||||
{
|
||||
this.logger = LoggerFactory.getLogger(endpointInstance.getClass());
|
||||
|
||||
|
@ -148,10 +147,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
if (actualTextMetadata.isMaxMessageSizeSet())
|
||||
session.setMaxTextMessageBufferSize(actualTextMetadata.getMaxMessageSize());
|
||||
|
||||
MethodHandle methodHandle = actualTextMetadata.getMethodHandle();
|
||||
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||
actualTextMetadata.setMethodHandle(methodHandle);
|
||||
MethodHolder methodHolder = actualTextMetadata.getMethodHolder();
|
||||
methodHolder = InvokerUtils.bindTo(methodHolder, endpointInstance, endpointConfig, session);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHolder, session);
|
||||
actualTextMetadata.setMethodHolder(methodHolder);
|
||||
|
||||
textSink = JakartaWebSocketFrameHandlerFactory.createMessageSink(session, actualTextMetadata);
|
||||
textMetadata = actualTextMetadata;
|
||||
|
@ -163,10 +162,10 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
if (actualBinaryMetadata.isMaxMessageSizeSet())
|
||||
session.setMaxBinaryMessageBufferSize(actualBinaryMetadata.getMaxMessageSize());
|
||||
|
||||
MethodHandle methodHandle = actualBinaryMetadata.getMethodHandle();
|
||||
methodHandle = InvokerUtils.bindTo(methodHandle, endpointInstance, endpointConfig, session);
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHandle, session);
|
||||
actualBinaryMetadata.setMethodHandle(methodHandle);
|
||||
MethodHolder methodHolder = actualBinaryMetadata.getMethodHolder();
|
||||
methodHolder = InvokerUtils.bindTo(methodHolder, endpointInstance, endpointConfig, session);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.wrapNonVoidReturnType(methodHolder, session);
|
||||
actualBinaryMetadata.setMethodHolder(methodHolder);
|
||||
|
||||
binarySink = JakartaWebSocketFrameHandlerFactory.createMessageSink(session, actualBinaryMetadata);
|
||||
binaryMetadata = actualBinaryMetadata;
|
||||
|
@ -353,116 +352,88 @@ public class JakartaWebSocketFrameHandler implements FrameHandler
|
|||
|
||||
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Partial<T> handler)
|
||||
{
|
||||
try
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHolder(new JakartaMessagePartialMethodHolder<>(handler));
|
||||
byte basicType;
|
||||
// MessageHandler.Partial has no decoder support!
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(MessageHandler.Partial.class, "onMessage", MethodType.methodType(void.class, Object.class, boolean.class))
|
||||
.bindTo(handler);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
}
|
||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
}
|
||||
else if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Unable to add " + handler.getClass().getName() + " with type " + clazz + ": only supported types byte[], " + ByteBuffer.class.getName() +
|
||||
", " + String.class.getName());
|
||||
}
|
||||
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHandle(methodHandle);
|
||||
byte basicType;
|
||||
// MessageHandler.Partial has no decoder support!
|
||||
if (byte[].class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
}
|
||||
else if (ByteBuffer.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
}
|
||||
else if (String.class.isAssignableFrom(clazz))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setSinkClass(PartialStringMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException(
|
||||
"Unable to add " + handler.getClass().getName() + " with type " + clazz + ": only supported types byte[], " + ByteBuffer.class.getName() +
|
||||
", " + String.class.getName());
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to find method", e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to access " + handler.getClass().getName(), e);
|
||||
}
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
|
||||
public <T> void addMessageHandler(Class<T> clazz, MessageHandler.Whole<T> handler)
|
||||
{
|
||||
try
|
||||
MethodHolder methodHolder = new JakartaMessageWholeMethodHolder<>(handler);
|
||||
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(MessageHandler.Whole.class, "onMessage", MethodType.methodType(void.class, Object.class))
|
||||
.bindTo(handler);
|
||||
|
||||
if (PongMessage.class.isAssignableFrom(clazz))
|
||||
{
|
||||
assertBasicTypeNotRegistered(OpCode.PONG, handler);
|
||||
this.pongHandle = methodHandle;
|
||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||
return;
|
||||
}
|
||||
|
||||
AvailableDecoders availableDecoders = session.getDecoders();
|
||||
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||
if (registeredDecoder == null)
|
||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||
|
||||
// Create the message metadata specific to the MessageHandler type.
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHandle(methodHandle);
|
||||
byte basicType;
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Unable to add " + handler.getClass().getName() + ": type " + clazz + " is unrecognized by declared decoders");
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
assertBasicTypeNotRegistered(OpCode.PONG, handler);
|
||||
this.pongHandle = methodHolder;
|
||||
registerMessageHandler(OpCode.PONG, clazz, handler, null);
|
||||
return;
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
||||
AvailableDecoders availableDecoders = session.getDecoders();
|
||||
RegisteredDecoder registeredDecoder = availableDecoders.getFirstRegisteredDecoder(clazz);
|
||||
if (registeredDecoder == null)
|
||||
throw new IllegalStateException("Unable to find Decoder for type: " + clazz);
|
||||
|
||||
// Create the message metadata specific to the MessageHandler type.
|
||||
JakartaWebSocketMessageMetadata metadata = new JakartaWebSocketMessageMetadata();
|
||||
metadata.setMethodHolder(methodHolder);
|
||||
byte basicType;
|
||||
if (registeredDecoder.implementsInterface(Decoder.Binary.class))
|
||||
{
|
||||
throw new IllegalStateException("Unable to find method", e);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryMessageSink.class);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
else if (registeredDecoder.implementsInterface(Decoder.BinaryStream.class))
|
||||
{
|
||||
throw new IllegalStateException("Unable to access " + handler.getClass().getName(), e);
|
||||
basicType = OpCode.BINARY;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getBinaryStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedBinaryStreamMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.Text.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextMessageSink.class);
|
||||
}
|
||||
else if (registeredDecoder.implementsInterface(Decoder.TextStream.class))
|
||||
{
|
||||
basicType = OpCode.TEXT;
|
||||
metadata.setRegisteredDecoders(availableDecoders.getTextStreamDecoders(clazz));
|
||||
metadata.setSinkClass(DecodedTextStreamMessageSink.class);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RuntimeException("Unable to add " + handler.getClass().getName() + ": type " + clazz + " is unrecognized by declared decoders");
|
||||
}
|
||||
|
||||
// Register the Metadata as a MessageHandler.
|
||||
registerMessageHandler(clazz, handler, basicType, metadata);
|
||||
}
|
||||
|
||||
private void assertBasicTypeNotRegistered(byte basicWebSocketType, MessageHandler replacement)
|
||||
|
|
|
@ -52,25 +52,11 @@ import org.eclipse.jetty.websocket.core.messages.PartialByteArrayMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.PartialByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
|
||||
public abstract class JakartaWebSocketFrameHandlerFactory
|
||||
{
|
||||
private static final MethodHandle FILTER_RETURN_TYPE_METHOD;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
FILTER_RETURN_TYPE_METHOD = getServerMethodHandleLookup()
|
||||
.findVirtual(JakartaWebSocketSession.class, "filterReturnType", MethodType.methodType(void.class, Object.class));
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static InvokerUtils.Arg[] getArgsFor(Class<?> objectType)
|
||||
{
|
||||
return new InvokerUtils.Arg[]{new InvokerUtils.Arg(Session.class), new InvokerUtils.Arg(objectType).required()};
|
||||
|
@ -135,10 +121,10 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (metadata == null)
|
||||
return null;
|
||||
|
||||
MethodHandle openHandle = metadata.getOpenHandle();
|
||||
MethodHandle closeHandle = metadata.getCloseHandle();
|
||||
MethodHandle errorHandle = metadata.getErrorHandle();
|
||||
MethodHandle pongHandle = metadata.getPongHandle();
|
||||
MethodHolder openHandle = MethodHolder.from(metadata.getOpenHandle());
|
||||
MethodHolder closeHandle = MethodHolder.from(metadata.getCloseHandle());
|
||||
MethodHolder errorHandle = MethodHolder.from(metadata.getErrorHandle());
|
||||
MethodHolder pongHandle = MethodHolder.from(metadata.getPongHandle());
|
||||
|
||||
JakartaWebSocketMessageMetadata textMetadata = JakartaWebSocketMessageMetadata.copyOf(metadata.getTextMetadata());
|
||||
JakartaWebSocketMessageMetadata binaryMetadata = JakartaWebSocketMessageMetadata.copyOf(metadata.getBinaryMetadata());
|
||||
|
@ -156,9 +142,9 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
pongHandle = bindTemplateVariables(pongHandle, namedVariables, pathParams);
|
||||
|
||||
if (textMetadata != null)
|
||||
textMetadata.setMethodHandle(bindTemplateVariables(textMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||
textMetadata.setMethodHolder(bindTemplateVariables(textMetadata.getMethodHolder(), namedVariables, pathParams));
|
||||
if (binaryMetadata != null)
|
||||
binaryMetadata.setMethodHandle(bindTemplateVariables(binaryMetadata.getMethodHandle(), namedVariables, pathParams));
|
||||
binaryMetadata.setMethodHolder(bindTemplateVariables(binaryMetadata.getMethodHolder(), namedVariables, pathParams));
|
||||
}
|
||||
|
||||
openHandle = InvokerUtils.bindTo(openHandle, endpoint);
|
||||
|
@ -190,15 +176,15 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (AbstractDecodedMessageSink.class.isAssignableFrom(msgMetadata.getSinkClass()))
|
||||
{
|
||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, List.class));
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, List.class));
|
||||
List<RegisteredDecoder> registeredDecoders = msgMetadata.getRegisteredDecoders();
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), registeredDecoders);
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHolder(), registeredDecoders);
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodHandle ctorHandle = lookup.findConstructor(msgMetadata.getSinkClass(),
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHandle(), true);
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgMetadata.getMethodHolder(), true);
|
||||
}
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
@ -219,23 +205,19 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
}
|
||||
}
|
||||
|
||||
public static MethodHandle wrapNonVoidReturnType(MethodHandle handle, JakartaWebSocketSession session)
|
||||
static MethodHolder wrapNonVoidReturnType(MethodHolder handle, JakartaWebSocketSession session)
|
||||
{
|
||||
if (handle == null)
|
||||
return null;
|
||||
|
||||
if (handle.type().returnType() == Void.TYPE)
|
||||
if (handle.returnType() == Void.TYPE)
|
||||
return handle;
|
||||
|
||||
// Technique from https://stackoverflow.com/questions/48505787/methodhandle-with-general-non-void-return-filter
|
||||
|
||||
// Change the return type of the to be Object so it will match exact with JakartaWebSocketSession.filterReturnType(Object)
|
||||
handle = handle.asType(handle.type().changeReturnType(Object.class));
|
||||
|
||||
// Filter the method return type to a call to JakartaWebSocketSession.filterReturnType() bound to this session
|
||||
handle = MethodHandles.filterReturnValue(handle, FILTER_RETURN_TYPE_METHOD.bindTo(session));
|
||||
|
||||
return handle;
|
||||
return args ->
|
||||
{
|
||||
session.filterReturnType(handle.invoke(args));
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
private MethodHandle toMethodHandle(MethodHandles.Lookup lookup, Method method)
|
||||
|
@ -252,7 +234,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
|
||||
protected JakartaWebSocketFrameHandlerMetadata createEndpointMetadata(EndpointConfig endpointConfig)
|
||||
{
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig, container.getWebSocketComponents());
|
||||
JakartaWebSocketFrameHandlerMetadata metadata = new JakartaWebSocketFrameHandlerMetadata(endpointConfig, components);
|
||||
MethodHandles.Lookup lookup = getServerMethodHandleLookup();
|
||||
|
||||
Method openMethod = ReflectUtils.findMethod(Endpoint.class, "onOpen", Session.class, EndpointConfig.class);
|
||||
|
@ -360,7 +342,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialStringMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setTextMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -370,7 +352,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialByteBufferMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -380,7 +362,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
if (methodHandle != null)
|
||||
{
|
||||
msgMetadata.setSinkClass(PartialByteArrayMessageSink.class);
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
metadata.setBinaryMetadata(msgMetadata, onMsg);
|
||||
return true;
|
||||
}
|
||||
|
@ -423,7 +405,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
objectType = decoder.objectType;
|
||||
}
|
||||
MethodHandle methodHandle = getMethodHandle.apply(getArgsFor(objectType));
|
||||
msgMetadata.setMethodHandle(methodHandle);
|
||||
msgMetadata.setMethodHolder(MethodHolder.from(methodHandle));
|
||||
|
||||
// Set the sinkClass and then set the MessageMetadata on the FrameHandlerMetadata
|
||||
if (interfaceType.equals(Decoder.Text.class))
|
||||
|
@ -508,7 +490,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
* have been statically assigned a converted value (and removed from the resulting {@link MethodHandle#type()}, or null if
|
||||
* no {@code target} MethodHandle was provided.
|
||||
*/
|
||||
public static MethodHandle bindTemplateVariables(MethodHandle target, String[] namedVariables, Map<String, String> templateValues)
|
||||
public static MethodHolder bindTemplateVariables(MethodHolder target, String[] namedVariables, Map<String, String> templateValues)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
|
@ -517,7 +499,7 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
|
||||
final int IDX = 1;
|
||||
|
||||
MethodHandle retHandle = target;
|
||||
MethodHolder retHandle = target;
|
||||
|
||||
if ((templateValues == null) || (templateValues.isEmpty()))
|
||||
{
|
||||
|
@ -527,54 +509,54 @@ public abstract class JakartaWebSocketFrameHandlerFactory
|
|||
for (String variableName : namedVariables)
|
||||
{
|
||||
String strValue = templateValues.get(variableName);
|
||||
Class<?> type = retHandle.type().parameterType(IDX);
|
||||
Class<?> type = retHandle.parameterType(IDX);
|
||||
try
|
||||
{
|
||||
if (String.class.isAssignableFrom(type))
|
||||
{
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, strValue);
|
||||
retHandle = retHandle.bindTo(strValue, IDX);
|
||||
}
|
||||
else if (Integer.class.isAssignableFrom(type) || Integer.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Integer intValue = Integer.parseInt(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, intValue);
|
||||
retHandle = retHandle.bindTo(intValue, IDX);
|
||||
}
|
||||
else if (Long.class.isAssignableFrom(type) || Long.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Long longValue = Long.parseLong(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, longValue);
|
||||
retHandle = retHandle.bindTo(longValue, IDX);
|
||||
}
|
||||
else if (Short.class.isAssignableFrom(type) || Short.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Short shortValue = Short.parseShort(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, shortValue);
|
||||
retHandle = retHandle.bindTo(shortValue, IDX);
|
||||
}
|
||||
else if (Float.class.isAssignableFrom(type) || Float.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Float floatValue = Float.parseFloat(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, floatValue);
|
||||
retHandle = retHandle.bindTo(floatValue, IDX);
|
||||
}
|
||||
else if (Double.class.isAssignableFrom(type) || Double.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Double doubleValue = Double.parseDouble(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, doubleValue);
|
||||
retHandle = retHandle.bindTo(doubleValue, IDX);
|
||||
}
|
||||
else if (Boolean.class.isAssignableFrom(type) || Boolean.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Boolean boolValue = Boolean.parseBoolean(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, boolValue);
|
||||
retHandle = retHandle.bindTo(boolValue, IDX);
|
||||
}
|
||||
else if (Character.class.isAssignableFrom(type) || Character.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
if (strValue.length() != 1)
|
||||
throw new IllegalArgumentException("Invalid Size");
|
||||
Character charValue = strValue.charAt(0);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, charValue);
|
||||
retHandle = retHandle.bindTo(charValue, IDX);
|
||||
}
|
||||
else if (Byte.class.isAssignableFrom(type) || Byte.TYPE.isAssignableFrom(type))
|
||||
{
|
||||
Byte b = Byte.parseByte(strValue);
|
||||
retHandle = MethodHandles.insertArguments(retHandle, IDX, b);
|
||||
retHandle = retHandle.bindTo(b, IDX);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -13,15 +13,15 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class JakartaWebSocketMessageMetadata
|
||||
{
|
||||
private MethodHandle methodHandle;
|
||||
private MethodHolder methodHolder;
|
||||
private Class<? extends MessageSink> sinkClass;
|
||||
private List<RegisteredDecoder> registeredDecoders;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class JakartaWebSocketMessageMetadata
|
|||
return null;
|
||||
|
||||
JakartaWebSocketMessageMetadata copy = new JakartaWebSocketMessageMetadata();
|
||||
copy.methodHandle = metadata.methodHandle;
|
||||
copy.methodHolder = metadata.methodHolder;
|
||||
copy.sinkClass = metadata.sinkClass;
|
||||
copy.registeredDecoders = metadata.registeredDecoders;
|
||||
copy.maxMessageSize = metadata.maxMessageSize;
|
||||
|
@ -58,14 +58,14 @@ public class JakartaWebSocketMessageMetadata
|
|||
this.maxMessageSizeSet = true;
|
||||
}
|
||||
|
||||
public MethodHandle getMethodHandle()
|
||||
public MethodHolder getMethodHolder()
|
||||
{
|
||||
return methodHandle;
|
||||
return methodHolder;
|
||||
}
|
||||
|
||||
public void setMethodHandle(MethodHandle methodHandle)
|
||||
public void setMethodHolder(MethodHolder methodHolder)
|
||||
{
|
||||
this.methodHandle = methodHandle;
|
||||
this.methodHolder = methodHolder;
|
||||
}
|
||||
|
||||
public Class<? extends MessageSink> getSinkClass()
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -25,6 +24,7 @@ import org.eclipse.jetty.websocket.core.CoreSession;
|
|||
import org.eclipse.jetty.websocket.core.Frame;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -32,12 +32,12 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AbstractDecodedMessageSink.class);
|
||||
|
||||
private final MethodHandle _methodHandle;
|
||||
private final MethodHolder _methodHolder;
|
||||
private final MessageSink _messageSink;
|
||||
|
||||
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHandle methodHandle)
|
||||
public AbstractDecodedMessageSink(CoreSession coreSession, MethodHolder methodHolder)
|
||||
{
|
||||
_methodHandle = methodHandle;
|
||||
_methodHolder = methodHolder;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
try
|
||||
{
|
||||
_methodHandle.invoke(message);
|
||||
_methodHolder.invoke(message);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -67,7 +67,7 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
}
|
||||
|
||||
/**
|
||||
* @return a message sink which will first decode the message then pass it to {@link #_methodHandle}.
|
||||
* @return a message sink which will first decode the message then pass it to {@link #_methodHolder}.
|
||||
* @throws Exception for any error in creating the message sink.
|
||||
*/
|
||||
abstract MessageSink newMessageSink(CoreSession coreSession) throws Exception;
|
||||
|
@ -90,9 +90,9 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
protected final List<T> _decoders;
|
||||
|
||||
public Basic(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public Basic(CoreSession coreSession, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(coreSession, methodHandle);
|
||||
super(coreSession, methodHolder);
|
||||
if (decoders.isEmpty())
|
||||
throw new IllegalArgumentException("Require at least one decoder for " + this.getClass());
|
||||
_decoders = decoders.stream()
|
||||
|
@ -105,9 +105,9 @@ public abstract class AbstractDecodedMessageSink implements MessageSink
|
|||
{
|
||||
protected final T _decoder;
|
||||
|
||||
public Stream(CoreSession coreSession, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public Stream(CoreSession coreSession, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(coreSession, methodHandle);
|
||||
super(coreSession, methodHolder);
|
||||
if (decoders.size() != 1)
|
||||
throw new IllegalArgumentException("Require exactly one decoder for " + this.getClass());
|
||||
_decoder = decoders.get(0).getInstance();
|
||||
|
|
|
@ -13,20 +13,19 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.ByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -34,18 +33,23 @@ public class DecodedBinaryMessageSink<T> extends AbstractDecodedMessageSink.Basi
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DecodedBinaryMessageSink.class);
|
||||
|
||||
public DecodedBinaryMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedBinaryMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedBinaryMessageSink.class, "onWholeMessage", MethodType.methodType(void.class, ByteBuffer.class))
|
||||
.bindTo(this);
|
||||
return new ByteBufferMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onWholeMessage((ByteBuffer)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new ByteBufferMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onWholeMessage(ByteBuffer wholeMessage)
|
||||
|
|
|
@ -15,34 +15,38 @@ package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class DecodedBinaryStreamMessageSink<T> extends AbstractDecodedMessageSink.Stream<Decoder.BinaryStream<T>>
|
||||
{
|
||||
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedBinaryStreamMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedBinaryStreamMessageSink.class, "onStreamStart", MethodType.methodType(void.class, InputStream.class))
|
||||
.bindTo(this);
|
||||
return new InputStreamMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onStreamStart((InputStream)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new InputStreamMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onStreamStart(InputStream stream)
|
||||
|
|
|
@ -13,19 +13,18 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -33,18 +32,23 @@ public class DecodedTextMessageSink<T> extends AbstractDecodedMessageSink.Basic<
|
|||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DecodedTextMessageSink.class);
|
||||
|
||||
public DecodedTextMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedTextMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws NoSuchMethodException, IllegalAccessException
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(getClass(), "onMessage", MethodType.methodType(void.class, String.class))
|
||||
.bindTo(this);
|
||||
return new StringMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onMessage((String)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new StringMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onMessage(String wholeMessage)
|
||||
|
|
|
@ -15,34 +15,38 @@ package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.websocket.CloseReason;
|
||||
import jakarta.websocket.DecodeException;
|
||||
import jakarta.websocket.Decoder;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.CoreSession;
|
||||
import org.eclipse.jetty.websocket.core.exception.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public class DecodedTextStreamMessageSink<T> extends AbstractDecodedMessageSink.Stream<Decoder.TextStream<T>>
|
||||
{
|
||||
public DecodedTextStreamMessageSink(CoreSession session, MethodHandle methodHandle, List<RegisteredDecoder> decoders)
|
||||
public DecodedTextStreamMessageSink(CoreSession session, MethodHolder methodHolder, List<RegisteredDecoder> decoders)
|
||||
{
|
||||
super(session, methodHandle, decoders);
|
||||
super(session, methodHolder, decoders);
|
||||
}
|
||||
|
||||
@Override
|
||||
MessageSink newMessageSink(CoreSession coreSession) throws Exception
|
||||
MessageSink newMessageSink(CoreSession coreSession)
|
||||
{
|
||||
MethodHandle methodHandle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup()
|
||||
.findVirtual(DecodedTextStreamMessageSink.class, "onStreamStart", MethodType.methodType(void.class, Reader.class))
|
||||
.bindTo(this);
|
||||
return new ReaderMessageSink(coreSession, methodHandle, true);
|
||||
MethodHolder methodHolder = args ->
|
||||
{
|
||||
if (args.length != 1)
|
||||
throw new WrongMethodTypeException(String.format("Expected %s params but had %s", 1, args.length));
|
||||
onStreamStart((Reader)args[0]);
|
||||
return null;
|
||||
};
|
||||
|
||||
return new ReaderMessageSink(coreSession, methodHolder, true);
|
||||
}
|
||||
|
||||
public void onStreamStart(Reader reader)
|
||||
|
|
|
@ -23,6 +23,7 @@ import jakarta.websocket.Decoder;
|
|||
import org.eclipse.jetty.ee9.websocket.jakarta.common.AbstractSessionTest;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
|
||||
public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
||||
{
|
||||
|
@ -43,7 +44,7 @@ public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
|||
return List.of(new RegisteredDecoder(clazz, interfaceType, objectType, ClientEndpointConfig.Builder.create().build(), components));
|
||||
}
|
||||
|
||||
public <T> MethodHandle getAcceptHandle(Consumer<T> copy, Class<T> type)
|
||||
public <T> MethodHolder getAcceptHandle(Consumer<T> copy, Class<T> type)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -51,7 +52,7 @@ public abstract class AbstractMessageSinkTest extends AbstractSessionTest
|
|||
String name = "accept";
|
||||
MethodType methodType = MethodType.methodType(void.class, type);
|
||||
MethodHandle handle = JakartaWebSocketFrameHandlerFactory.getServerMethodHandleLookup().findVirtual(refc, name, methodType);
|
||||
return handle.bindTo(copy);
|
||||
return MethodHolder.from(handle.bindTo(copy));
|
||||
}
|
||||
catch (NoSuchMethodException | IllegalAccessException e)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -31,6 +30,7 @@ import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder
|
|||
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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -45,7 +45,7 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(AbstractSessionTest.session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -67,7 +67,7 @@ public class DecodedBinaryMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryMessageSink<Calendar> sink = new DecodedBinaryMessageSink<>(AbstractSessionTest.session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -33,6 +32,7 @@ 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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -47,7 +47,7 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class DecodedBinaryStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Calendar> copyFuture = new CompletableFuture<>();
|
||||
DecodedCalendarCopy copy = new DecodedCalendarCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Calendar.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedBinaryStreamMessageSink<Calendar> sink = new DecodedBinaryStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -31,6 +30,7 @@ import org.eclipse.jetty.ee9.websocket.jakarta.common.decoders.RegisteredDecoder
|
|||
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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -45,7 +45,7 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -62,7 +62,7 @@ public class DecodedTextMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextMessageSink<Calendar> sink = new DecodedTextMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
|
@ -34,6 +33,7 @@ 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.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -48,7 +48,7 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class DecodedTextStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<Date> copyFuture = new CompletableFuture<>();
|
||||
DecodedDateCopy copy = new DecodedDateCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Date.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Date.class);
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(GmtDecoder.class, Calendar.class);
|
||||
DecodedTextStreamMessageSink<Calendar> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), copyHandle, decoders);
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -33,6 +32,7 @@ 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.core.messages.InputStreamMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
@ -46,7 +46,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream1Message1Frame() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
|
@ -63,7 +63,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream2Messages2Frames() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback fin1Callback = new FutureCallback();
|
||||
|
@ -91,7 +91,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream1Message3Frames() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
|
@ -113,7 +113,7 @@ public class InputStreamMessageSinkTest extends AbstractMessageSinkTest
|
|||
public void testInputStream1Message4FramesEmptyFin() throws InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
InputStreamCopy copy = new InputStreamCopy();
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, InputStream.class);
|
||||
InputStreamMessageSink sink = new InputStreamMessageSink(AbstractSessionTest.session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
|
|
|
@ -16,7 +16,6 @@ package org.eclipse.jetty.ee9.websocket.jakarta.common.messages;
|
|||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -28,6 +27,7 @@ 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.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -40,7 +40,7 @@ public class ReaderMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<StringWriter> copyFuture = new CompletableFuture<>();
|
||||
ReaderCopy copy = new ReaderCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback finCallback = new FutureCallback();
|
||||
|
@ -56,7 +56,7 @@ public class ReaderMessageSinkTest extends AbstractMessageSinkTest
|
|||
{
|
||||
CompletableFuture<StringWriter> copyFuture = new CompletableFuture<>();
|
||||
ReaderCopy copy = new ReaderCopy(copyFuture);
|
||||
MethodHandle copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
MethodHolder copyHandle = getAcceptHandle(copy, Reader.class);
|
||||
ReaderMessageSink sink = new ReaderMessageSink(session.getCoreSession(), copyHandle, true);
|
||||
|
||||
FutureCallback callback1 = new FutureCallback();
|
||||
|
|
|
@ -23,6 +23,7 @@ import jakarta.websocket.Session;
|
|||
import org.eclipse.jetty.ee9.websocket.jakarta.common.JakartaWebSocketFrameHandlerFactory;
|
||||
import org.eclipse.jetty.util.annotation.Name;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -57,6 +58,12 @@ public class InvokerUtilsStaticParamsTest
|
|||
|
||||
private static MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
private MethodHolder getMethodHolder(Method method, String[] namedVariables, InvokerUtils.Arg... args)
|
||||
{
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, args);
|
||||
return MethodHolder.from(methodHandle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyParamString() throws Throwable
|
||||
{
|
||||
|
@ -70,21 +77,21 @@ 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(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("fruit", "pear");
|
||||
|
||||
// Bind the static values, in same order as declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke();
|
||||
String result = (String)methodHolder.invoke();
|
||||
assertThat("Result", result, is("onFruit('pear')"));
|
||||
}
|
||||
|
||||
|
@ -99,21 +106,21 @@ public class InvokerUtilsStaticParamsTest
|
|||
};
|
||||
|
||||
// Get basic method handle (without a instance to call against) - this is what the metadata stores
|
||||
MethodHandle methodHandle = InvokerUtils.mutatedInvoker(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("count", "2222");
|
||||
|
||||
// Bind the static values for the variables, in same order as the variables were declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke();
|
||||
String result = (String)methodHolder.invoke();
|
||||
assertThat("Result", result, is("onCount(2222)"));
|
||||
}
|
||||
|
||||
|
@ -130,21 +137,21 @@ public class InvokerUtilsStaticParamsTest
|
|||
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(lookup, Foo.class, method, new NameParamIdentifier(), namedVariables, ARG_LABEL);
|
||||
MethodHolder methodHolder = getMethodHolder(method, namedVariables, ARG_LABEL);
|
||||
|
||||
// Some point later an actual instance is needed, which has static named parameters
|
||||
Map<String, String> templateValues = new HashMap<>();
|
||||
templateValues.put("count", "444");
|
||||
|
||||
// Bind the static values for the variables, in same order as the variables were declared
|
||||
methodHandle = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHandle, namedVariables, templateValues);
|
||||
methodHolder = JakartaWebSocketFrameHandlerFactory.bindTemplateVariables(methodHolder, namedVariables, templateValues);
|
||||
|
||||
// Assign an instance to call.
|
||||
Foo foo = new Foo();
|
||||
methodHandle = methodHandle.bindTo(foo);
|
||||
methodHolder = methodHolder.bindTo(foo);
|
||||
|
||||
// Call method against instance
|
||||
String result = (String)methodHandle.invoke("cherry");
|
||||
String result = (String)methodHolder.invoke("cherry");
|
||||
assertThat("Result", result, is("onLabeledCount('cherry', 444)"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ 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.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -80,7 +81,7 @@ public class DecoderTextStreamTest extends AbstractClientSessionTest
|
|||
});
|
||||
|
||||
List<RegisteredDecoder> decoders = toRegisteredDecoderList(QuotesDecoder.class, Quotes.class);
|
||||
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), quoteHandle, decoders);
|
||||
DecodedTextStreamMessageSink<Quotes> sink = new DecodedTextStreamMessageSink<>(session.getCoreSession(), MethodHolder.from(quoteHandle), decoders);
|
||||
|
||||
List<FutureCallback> callbacks = new ArrayList<>();
|
||||
FutureCallback finCallback = null;
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
package org.eclipse.jetty.ee9.websocket.common;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.ee9.websocket.api.BatchMode;
|
||||
|
@ -42,6 +42,7 @@ import org.eclipse.jetty.websocket.core.exception.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.core.exception.WebSocketTimeoutException;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -61,16 +62,16 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
private final Object endpointInstance;
|
||||
private final BatchMode batchMode;
|
||||
private final AtomicBoolean closeNotified = new AtomicBoolean();
|
||||
private MethodHandle openHandle;
|
||||
private MethodHandle closeHandle;
|
||||
private MethodHandle errorHandle;
|
||||
private MethodHandle textHandle;
|
||||
private MethodHolder openHandle;
|
||||
private MethodHolder closeHandle;
|
||||
private MethodHolder errorHandle;
|
||||
private MethodHolder textHandle;
|
||||
private final Class<? extends MessageSink> textSinkClass;
|
||||
private MethodHandle binaryHandle;
|
||||
private MethodHolder binaryHandle;
|
||||
private final Class<? extends MessageSink> binarySinkClass;
|
||||
private MethodHandle frameHandle;
|
||||
private MethodHandle pingHandle;
|
||||
private MethodHandle pongHandle;
|
||||
private MethodHolder frameHandle;
|
||||
private MethodHolder pingHandle;
|
||||
private MethodHolder pongHandle;
|
||||
private UpgradeRequest upgradeRequest;
|
||||
private UpgradeResponse upgradeResponse;
|
||||
|
||||
|
@ -85,12 +86,12 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
|
||||
public JettyWebSocketFrameHandler(WebSocketContainer container,
|
||||
Object endpointInstance,
|
||||
MethodHandle openHandle, MethodHandle closeHandle, MethodHandle errorHandle,
|
||||
MethodHandle textHandle, MethodHandle binaryHandle,
|
||||
MethodHolder openHandle, MethodHolder closeHandle, MethodHolder errorHandle,
|
||||
MethodHolder textHandle, MethodHolder binaryHandle,
|
||||
Class<? extends MessageSink> textSinkClass,
|
||||
Class<? extends MessageSink> binarySinkClass,
|
||||
MethodHandle frameHandle,
|
||||
MethodHandle pingHandle, MethodHandle pongHandle,
|
||||
MethodHolder frameHandle,
|
||||
MethodHolder pingHandle, MethodHolder pongHandle,
|
||||
BatchMode batchMode,
|
||||
Configuration.Customizer customizer)
|
||||
{
|
||||
|
@ -163,15 +164,13 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
pingHandle = InvokerUtils.bindTo(pingHandle, session);
|
||||
pongHandle = InvokerUtils.bindTo(pongHandle, session);
|
||||
|
||||
Executor executor = coreSession.getWebSocketComponents().getExecutor();
|
||||
if (textHandle != null)
|
||||
textSink = JettyWebSocketFrameHandlerFactory.createMessageSink(textHandle, textSinkClass, session);
|
||||
|
||||
textSink = JettyWebSocketFrameHandlerFactory.createMessageSink(textHandle, textSinkClass, executor, session);
|
||||
if (binaryHandle != null)
|
||||
binarySink = JettyWebSocketFrameHandlerFactory.createMessageSink(binaryHandle, binarySinkClass, session);
|
||||
|
||||
binarySink = JettyWebSocketFrameHandlerFactory.createMessageSink(binaryHandle, binarySinkClass, executor, session);
|
||||
if (openHandle != null)
|
||||
openHandle.invoke();
|
||||
|
||||
if (session.isOpen())
|
||||
container.notifySessionListeners((listener) -> listener.onWebSocketSessionOpened(session));
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.nio.ByteBuffer;
|
|||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.ee9.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.ee9.websocket.api.Frame;
|
||||
|
@ -58,6 +59,7 @@ import org.eclipse.jetty.websocket.core.messages.PartialStringMessageSink;
|
|||
import org.eclipse.jetty.websocket.core.messages.ReaderMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.InvokerUtils;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.eclipse.jetty.websocket.core.util.ReflectUtils;
|
||||
|
||||
/**
|
||||
|
@ -165,16 +167,16 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
{
|
||||
JettyWebSocketFrameHandlerMetadata metadata = getMetadata(endpointInstance.getClass());
|
||||
|
||||
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 MethodHolder openHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getOpenHandle()), endpointInstance);
|
||||
final MethodHolder closeHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getCloseHandle()), endpointInstance);
|
||||
final MethodHolder errorHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getErrorHandle()), endpointInstance);
|
||||
final MethodHolder textHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getTextHandle()), endpointInstance);
|
||||
final MethodHolder binaryHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getBinaryHandle()), endpointInstance);
|
||||
final Class<? extends MessageSink> textSinkClass = metadata.getTextSink();
|
||||
final Class<? extends MessageSink> binarySinkClass = metadata.getBinarySink();
|
||||
final MethodHandle frameHandle = InvokerUtils.bindTo(metadata.getFrameHandle(), endpointInstance);
|
||||
final MethodHandle pingHandle = InvokerUtils.bindTo(metadata.getPingHandle(), endpointInstance);
|
||||
final MethodHandle pongHandle = InvokerUtils.bindTo(metadata.getPongHandle(), endpointInstance);
|
||||
final MethodHolder frameHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getFrameHandle()), endpointInstance);
|
||||
final MethodHolder pingHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getPingHandle()), endpointInstance);
|
||||
final MethodHolder pongHandle = InvokerUtils.bindTo(MethodHolder.from(metadata.getPongHandle()), endpointInstance);
|
||||
BatchMode batchMode = metadata.getBatchMode();
|
||||
|
||||
// Decorate the endpointInstance while we are still upgrading for access to things like HttpSession.
|
||||
|
@ -191,7 +193,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
metadata);
|
||||
}
|
||||
|
||||
public static MessageSink createMessageSink(MethodHandle msgHandle, Class<? extends MessageSink> sinkClass, WebSocketSession session)
|
||||
public static MessageSink createMessageSink(MethodHolder msgHandle, Class<? extends MessageSink> sinkClass, Executor executor, WebSocketSession session)
|
||||
{
|
||||
if (msgHandle == null)
|
||||
return null;
|
||||
|
@ -202,7 +204,7 @@ public class JettyWebSocketFrameHandlerFactory extends ContainerLifeCycle
|
|||
{
|
||||
MethodHandles.Lookup lookup = JettyWebSocketFrameHandlerFactory.getServerMethodHandleLookup();
|
||||
MethodHandle ctorHandle = lookup.findConstructor(sinkClass,
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHandle.class, boolean.class));
|
||||
MethodType.methodType(void.class, CoreSession.class, MethodHolder.class, boolean.class));
|
||||
return (MessageSink)ctorHandle.invoke(session.getCoreSession(), msgHandle, true);
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.eclipse.jetty.websocket.core.OpCode;
|
|||
import org.eclipse.jetty.websocket.core.messages.ByteBufferMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.MessageSink;
|
||||
import org.eclipse.jetty.websocket.core.messages.StringMessageSink;
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -96,7 +97,7 @@ public class OutgoingMessageCapture extends CoreSession.Empty implements CoreSes
|
|||
String event = String.format("TEXT:fin=%b:len=%d", frame.isFin(), frame.getPayloadLength());
|
||||
LOG.debug(event);
|
||||
events.offer(event);
|
||||
messageSink = new StringMessageSink(this, wholeTextHandle, true);
|
||||
messageSink = new StringMessageSink(this, MethodHolder.from(wholeTextHandle), true);
|
||||
break;
|
||||
}
|
||||
case OpCode.BINARY:
|
||||
|
@ -104,7 +105,7 @@ public class OutgoingMessageCapture extends CoreSession.Empty implements CoreSes
|
|||
String event = String.format("BINARY:fin=%b:len=%d", frame.isFin(), frame.getPayloadLength());
|
||||
LOG.debug(event);
|
||||
events.offer(event);
|
||||
messageSink = new ByteBufferMessageSink(this, wholeBinaryHandle, true);
|
||||
messageSink = new ByteBufferMessageSink(this, MethodHolder.from(wholeBinaryHandle), true);
|
||||
break;
|
||||
}
|
||||
case OpCode.CONTINUATION:
|
||||
|
|
|
@ -41,6 +41,14 @@
|
|||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>jetty-websocket-jetty-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>jetty-websocket-jetty-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jmh</groupId>
|
||||
<artifactId>jmh-core</artifactId>
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.jmh;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.util.MethodHolder;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Threads;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
@Threads(4)
|
||||
@Warmup(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Measurement(iterations = 7, time = 500, timeUnit = TimeUnit.MILLISECONDS)
|
||||
public class MethodHolderBenchmark
|
||||
{
|
||||
private MethodHandle methodHandle;
|
||||
private MethodHolder methodHolderNonBinding;
|
||||
private MethodHolder methodHolderBinding;
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void setupTrial(Blackhole blackhole) throws Throwable
|
||||
{
|
||||
MethodType methodType = MethodType.methodType(void.class, Blackhole.class, String.class, String.class);
|
||||
methodHandle = MethodHandles.lookup()
|
||||
.findVirtual(MethodHolderBenchmark.class, "consume", methodType);
|
||||
if (methodHandle == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
methodHolderBinding = MethodHolder.from(methodHandle, true);
|
||||
methodHolderBinding.bindTo(this);
|
||||
methodHolderBinding.bindTo(Objects.requireNonNull(blackhole));
|
||||
|
||||
methodHolderNonBinding = MethodHolder.from(methodHandle, false);
|
||||
methodHolderNonBinding.bindTo(this);
|
||||
methodHolderNonBinding.bindTo(Objects.requireNonNull(blackhole));
|
||||
|
||||
methodHandle = methodHandle.bindTo(this);
|
||||
methodHandle = methodHandle.bindTo(Objects.requireNonNull(blackhole));
|
||||
}
|
||||
|
||||
public void consume(Blackhole blackhole, String a, String b)
|
||||
{
|
||||
blackhole.consume(a);
|
||||
blackhole.consume(b);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode({Mode.Throughput})
|
||||
public void methodHandle() throws Throwable
|
||||
{
|
||||
methodHandle.invoke("test", "12");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode({Mode.Throughput})
|
||||
public void methodHolderNonBinding() throws Throwable
|
||||
{
|
||||
methodHolderNonBinding.invoke("test", "12");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@BenchmarkMode({Mode.Throughput})
|
||||
public void methodHolderBinding() throws Throwable
|
||||
{
|
||||
methodHolderBinding.invoke("test", "12");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws RunnerException
|
||||
{
|
||||
Options opt = new OptionsBuilder()
|
||||
.include(MethodHolderBenchmark.class.getSimpleName())
|
||||
.warmupIterations(5)
|
||||
.measurementIterations(10)
|
||||
.forks(1)
|
||||
.threads(1)
|
||||
.build();
|
||||
|
||||
new Runner(opt).run();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue