Ensure that javax.websocket Encoder/Decoder destroy method is called.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2021-04-20 11:11:05 +10:00
parent 4c98990cd9
commit ab08d1a1c6
6 changed files with 58 additions and 4 deletions

View File

@ -51,7 +51,7 @@ import org.testcontainers.utility.MountableFile;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@Disabled @Disabled("Disable this test so it doesn't run locally as it takes 1h+ to run.")
@Testcontainers @Testcontainers
public class AutobahnTests public class AutobahnTests
{ {

View File

@ -266,6 +266,10 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
{ {
notifyOnClose(closeStatus, callback); notifyOnClose(closeStatus, callback);
container.notifySessionListeners((listener) -> listener.onJavaxWebSocketSessionClosed(session)); container.notifySessionListeners((listener) -> listener.onJavaxWebSocketSessionClosed(session));
// Close AvailableEncoders and AvailableDecoders to call destroy() on any instances of Encoder/Encoder created.
session.getDecoders().close();
session.getEncoders().close();
} }
private void notifyOnClose(CloseStatus closeStatus, Callback callback) private void notifyOnClose(CloseStatus closeStatus, Callback callback)

View File

@ -207,4 +207,9 @@ public class AvailableDecoders implements Iterable<RegisteredDecoder>
{ {
return registeredDecoders.stream(); return registeredDecoders.stream();
} }
public void close()
{
registeredDecoders.forEach(RegisteredDecoder::destroyInstance);
}
} }

View File

@ -18,9 +18,13 @@ import javax.websocket.Decoder;
import javax.websocket.EndpointConfig; import javax.websocket.EndpointConfig;
import org.eclipse.jetty.websocket.javax.common.InitException; import org.eclipse.jetty.websocket.javax.common.InitException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RegisteredDecoder public class RegisteredDecoder
{ {
private static final Logger LOG = LoggerFactory.getLogger(RegisteredDecoder.class);
// The user supplied Decoder class // The user supplied Decoder class
public final Class<? extends Decoder> decoder; public final Class<? extends Decoder> decoder;
// The javax.websocket.Decoder.* type (eg: Decoder.Binary, Decoder.BinaryStream, Decoder.Text, Decoder.TextStream) // The javax.websocket.Decoder.* type (eg: Decoder.Binary, Decoder.BinaryStream, Decoder.Text, Decoder.TextStream)
@ -74,6 +78,23 @@ public class RegisteredDecoder
return (T)instance; return (T)instance;
} }
public void destroyInstance()
{
if (instance != null)
{
try
{
instance.destroy();
}
catch (Throwable t)
{
LOG.warn("Error destroying Decoder", t);
}
instance = null;
}
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -28,9 +28,14 @@ import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException;
import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException; import org.eclipse.jetty.websocket.core.exception.InvalidWebSocketException;
import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils; import org.eclipse.jetty.websocket.core.internal.util.ReflectUtils;
import org.eclipse.jetty.websocket.javax.common.InitException; import org.eclipse.jetty.websocket.javax.common.InitException;
import org.eclipse.jetty.websocket.javax.common.decoders.RegisteredDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AvailableEncoders implements Predicate<Class<?>> public class AvailableEncoders implements Predicate<Class<?>>
{ {
private static final Logger LOG = LoggerFactory.getLogger(RegisteredDecoder.class);
public static class RegisteredEncoder public static class RegisteredEncoder
{ {
public final Class<? extends Encoder> encoder; public final Class<? extends Encoder> encoder;
@ -62,6 +67,23 @@ public class AvailableEncoders implements Predicate<Class<?>>
return objectType.isAssignableFrom(type); return objectType.isAssignableFrom(type);
} }
public void destroyInstance()
{
if (instance != null)
{
try
{
instance.destroy();
}
catch (Throwable t)
{
LOG.warn("Error destroying Decoder", t);
}
instance = null;
}
}
@Override @Override
public String toString() public String toString()
{ {
@ -286,4 +308,9 @@ public class AvailableEncoders implements Predicate<Class<?>>
{ {
return registeredEncoders.stream().anyMatch(registered -> registered.isType(type)); return registeredEncoders.stream().anyMatch(registered -> registered.isType(type));
} }
public void close()
{
registeredEncoders.forEach(RegisteredEncoder::destroyInstance);
}
} }

View File

@ -37,7 +37,6 @@ import org.eclipse.jetty.websocket.javax.common.encoders.AvailableEncoders;
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer; import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.javax.tests.EchoSocket; import org.eclipse.jetty.websocket.javax.tests.EchoSocket;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -147,8 +146,6 @@ public class EncoderLifeCycleTest
} }
} }
// TODO: Encoder.destroy() is never called in Jetty 10.
@Disabled()
@ParameterizedTest @ParameterizedTest
@ValueSource(classes = {StringHolder.class, StringHolderSubtype.class}) @ValueSource(classes = {StringHolder.class, StringHolderSubtype.class})
public void testEncoderLifeCycle(Class<? extends StringHolder> clazz) throws Exception public void testEncoderLifeCycle(Class<? extends StringHolder> clazz) throws Exception