From f2ea8351b6cb2b5e8ceffd02680ba136ed639f2e Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 22 May 2014 13:12:39 -0700 Subject: [PATCH] 429390 - Decoders and Encoders are not registered for non-annotated ClientEndpoint + Adding EncoderTest to verify reported bug + Fixing SimpleEndpointMetadata to propagate the encoder/decoder list when present. --- .../websocket/jsr356/ClientContainer.java | 7 +- .../jsr356/client/SimpleEndpointMetadata.java | 12 + .../jetty/websocket/jsr356/EncoderTest.java | 316 ++++++++++++++++++ .../jsr356/server/ServerContainer.java | 2 +- .../server/SimpleServerEndpointMetadata.java | 7 +- .../common/test/BlockheadServer.java | 2 +- 6 files changed, 335 insertions(+), 11 deletions(-) create mode 100644 jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java index 6ba4d2284fa..e7722e5297d 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java @@ -34,6 +34,7 @@ import javax.websocket.ClientEndpoint; import javax.websocket.ClientEndpointConfig; import javax.websocket.DeploymentException; import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; import javax.websocket.Extension; import javax.websocket.Session; import javax.websocket.WebSocketContainer; @@ -199,7 +200,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont return client; } - public EndpointMetadata getClientEndpointMetadata(Class endpoint) + public EndpointMetadata getClientEndpointMetadata(Class endpoint, EndpointConfig config) { EndpointMetadata metadata = null; @@ -226,7 +227,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont // extends Endpoint @SuppressWarnings("unchecked") Class eendpoint = (Class)endpoint; - metadata = new SimpleEndpointMetadata(eendpoint); + metadata = new SimpleEndpointMetadata(eendpoint,config); } else { @@ -313,7 +314,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont public EndpointInstance newClientEndpointInstance(Object endpoint, ClientEndpointConfig config) { - EndpointMetadata metadata = getClientEndpointMetadata(endpoint.getClass()); + EndpointMetadata metadata = getClientEndpointMetadata(endpoint.getClass(),config); ClientEndpointConfig cec = config; if (config == null) { diff --git a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/SimpleEndpointMetadata.java b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/SimpleEndpointMetadata.java index 4a5c636369d..84049ca0f91 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/SimpleEndpointMetadata.java +++ b/jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/client/SimpleEndpointMetadata.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.websocket.jsr356.client; import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadataSet; import org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadataSet; @@ -34,10 +35,21 @@ public class SimpleEndpointMetadata implements EndpointMetadata private EncoderMetadataSet encoders; public SimpleEndpointMetadata(Class endpointClass) + { + this(endpointClass, null); + } + + public SimpleEndpointMetadata(Class endpointClass, EndpointConfig config) { this.endpointClass = endpointClass; this.decoders = new DecoderMetadataSet(); this.encoders = new EncoderMetadataSet(); + + if (config != null) + { + this.decoders.addAll(config.getDecoders()); + this.encoders.addAll(config.getEncoders()); + } } @Override diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java new file mode 100644 index 00000000000..6931999e1c9 --- /dev/null +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/EncoderTest.java @@ -0,0 +1,316 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356; + +import static org.hamcrest.Matchers.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.websocket.ClientEndpointConfig; +import javax.websocket.ContainerProvider; +import javax.websocket.EncodeException; +import javax.websocket.Encoder; +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.MessageHandler; +import javax.websocket.Session; +import javax.websocket.WebSocketContainer; + +import org.eclipse.jetty.toolchain.test.EventQueue; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestTracker; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.common.test.BlockheadServer; +import org.eclipse.jetty.websocket.common.test.BlockheadServer.ServerConnection; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class EncoderTest +{ + private static class EchoServer implements Runnable + { + private Thread thread; + private BlockheadServer server; + private ServerConnection sconnection; + private CountDownLatch connectLatch = new CountDownLatch(1); + + public EchoServer(BlockheadServer server) + { + this.server = server; + } + + @Override + public void run() + { + try + { + sconnection = server.accept(); + sconnection.setSoTimeout(60000); + sconnection.upgrade(); + sconnection.startEcho(); + } + catch (Exception e) + { + LOG.warn(e); + } + finally + { + connectLatch.countDown(); + } + } + + public void start() + { + this.thread = new Thread(this,"EchoServer"); + this.thread.start(); + } + + public void stop() + { + if (this.sconnection != null) + { + this.sconnection.stopEcho(); + try + { + this.sconnection.close(); + } + catch (IOException ignore) + { + /* ignore */ + } + } + } + } + + public static class Quotes + { + private String author; + private List quotes = new ArrayList<>(); + + public void addQuote(String quote) + { + quotes.add(quote); + } + + public String getAuthor() + { + return author; + } + + public List getQuotes() + { + return quotes; + } + + public void setAuthor(String author) + { + this.author = author; + } + } + + public static class QuotesEncoder implements Encoder.Text + { + @Override + public void destroy() + { + } + + @Override + public String encode(Quotes q) throws EncodeException + { + StringBuilder buf = new StringBuilder(); + buf.append("Author: ").append(q.getAuthor()); + buf.append(System.lineSeparator()); + for (String quote : q.quotes) + { + buf.append("Quote: ").append(quote); + buf.append(System.lineSeparator()); + } + return buf.toString(); + } + + @Override + public void init(EndpointConfig config) + { + } + } + + public static class QuotesSocket extends Endpoint implements MessageHandler.Whole + { + private Session session; + private EventQueue messageQueue = new EventQueue<>(); + + @Override + public void onMessage(String message) + { + messageQueue.add(message); + } + + @Override + public void onOpen(Session session, EndpointConfig config) + { + this.session = session; + this.session.addMessageHandler(this); + } + + public void write(Quotes quotes) throws IOException, EncodeException + { + LOG.debug("Writing Quotes: {}",quotes); + this.session.getBasicRemote().sendObject(quotes); + } + } + + private static final Logger LOG = Log.getLogger(EncoderTest.class); + + @Rule + public TestTracker tt = new TestTracker(); + private BlockheadServer server; + + private WebSocketContainer client; + + private void assertReceivedQuotes(String result, Quotes quotes) + { + Assert.assertThat("Quote Author",result,containsString("Author: " + quotes.getAuthor())); + for (String quote : quotes.quotes) + { + Assert.assertThat("Quote",result,containsString("Quote: " + quote)); + } + } + + private Quotes getQuotes(String filename) throws IOException + { + Quotes quotes = new Quotes(); + + // read file + File qfile = MavenTestingUtils.getTestResourceFile(filename); + try (FileReader reader = new FileReader(qfile); BufferedReader buf = new BufferedReader(reader)) + { + String line; + while ((line = buf.readLine()) != null) + { + switch (line.charAt(0)) + { + case 'a': + quotes.setAuthor(line.substring(2)); + break; + case 'q': + quotes.addQuote(line.substring(2)); + break; + } + } + } + + return quotes; + } + + @Before + public void initClient() + { + client = ContainerProvider.getWebSocketContainer(); + } + + @Before + public void startServer() throws Exception + { + server = new BlockheadServer(); + server.start(); + } + + @After + public void stopServer() throws Exception + { + server.stop(); + } + + @Test + public void testSingleQuotes() throws Exception + { + EchoServer eserver = new EchoServer(server); + try + { + eserver.start(); + + QuotesSocket quoter = new QuotesSocket(); + + ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create(); + List> encoders = new ArrayList<>(); + encoders.add(QuotesEncoder.class); + builder.encoders(encoders); + ClientEndpointConfig cec = builder.build(); + client.connectToServer(quoter,cec,server.getWsUri()); + + Quotes ben = getQuotes("quotes-ben.txt"); + quoter.write(ben); + + quoter.messageQueue.awaitEventCount(1,1000,TimeUnit.MILLISECONDS); + + String result = quoter.messageQueue.poll(); + assertReceivedQuotes(result,ben); + } + finally + { + eserver.stop(); + } + } + + @Test + public void testTwoQuotes() throws Exception + { + EchoServer eserver = new EchoServer(server); + try + { + eserver.start(); + + QuotesSocket quoter = new QuotesSocket(); + ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create(); + List> encoders = new ArrayList<>(); + encoders.add(QuotesEncoder.class); + builder.encoders(encoders); + ClientEndpointConfig cec = builder.build(); + client.connectToServer(quoter,cec,server.getWsUri()); + + Quotes ben = getQuotes("quotes-ben.txt"); + Quotes twain = getQuotes("quotes-twain.txt"); + quoter.write(ben); + quoter.write(twain); + + quoter.messageQueue.awaitEventCount(2,1000,TimeUnit.MILLISECONDS); + + String result = quoter.messageQueue.poll(); + assertReceivedQuotes(result,ben); + result = quoter.messageQueue.poll(); + assertReceivedQuotes(result,twain); + } + finally + { + eserver.stop(); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java index 1e065fadfe5..9b6e6f9eed1 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java @@ -57,7 +57,7 @@ public class ServerContainer extends ClientContainer implements javax.websocket. public EndpointInstance newClientEndpointInstance(Object endpoint, ServerEndpointConfig config, String path) { - EndpointMetadata metadata = getClientEndpointMetadata(endpoint.getClass()); + EndpointMetadata metadata = getClientEndpointMetadata(endpoint.getClass(),config); ServerEndpointConfig cec = config; if (config == null) { diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/SimpleServerEndpointMetadata.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/SimpleServerEndpointMetadata.java index 916326812f0..ebfd3996086 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/SimpleServerEndpointMetadata.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/SimpleServerEndpointMetadata.java @@ -29,13 +29,8 @@ public class SimpleServerEndpointMetadata extends SimpleEndpointMetadata impleme public SimpleServerEndpointMetadata(Class endpointClass, ServerEndpointConfig config) { - super(endpointClass); + super(endpointClass,config); this.config = config; - if (this.config != null) - { - getDecoders().addAll(config.getDecoders()); - getEncoders().addAll(config.getEncoders()); - } } @Override diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java index ecb712f281e..f4c4c391f98 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServer.java @@ -233,7 +233,7 @@ public class BlockheadServer { try { - write(WebSocketFrame.copy(frame)); + write(WebSocketFrame.copy(frame).setMasked(false)); } catch (IOException e) {