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.
This commit is contained in:
Joakim Erdfelt 2014-05-22 13:12:39 -07:00
parent 58ea1dd386
commit f2ea8351b6
6 changed files with 335 additions and 11 deletions

View File

@ -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<? extends Endpoint> eendpoint = (Class<? extends Endpoint>)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)
{

View File

@ -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<? extends Endpoint> endpointClass)
{
this(endpointClass, null);
}
public SimpleEndpointMetadata(Class<? extends Endpoint> 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

View File

@ -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<String> quotes = new ArrayList<>();
public void addQuote(String quote)
{
quotes.add(quote);
}
public String getAuthor()
{
return author;
}
public List<String> getQuotes()
{
return quotes;
}
public void setAuthor(String author)
{
this.author = author;
}
}
public static class QuotesEncoder implements Encoder.Text<Quotes>
{
@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<String>
{
private Session session;
private EventQueue<String> 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<Class<? extends Encoder>> 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<Class<? extends Encoder>> 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();
}
}
}

View File

@ -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)
{

View File

@ -29,13 +29,8 @@ public class SimpleServerEndpointMetadata extends SimpleEndpointMetadata impleme
public SimpleServerEndpointMetadata(Class<? extends Endpoint> endpointClass, ServerEndpointConfig config)
{
super(endpointClass);
super(endpointClass,config);
this.config = config;
if (this.config != null)
{
getDecoders().addAll(config.getDecoders());
getEncoders().addAll(config.getEncoders());
}
}
@Override

View File

@ -233,7 +233,7 @@ public class BlockheadServer
{
try
{
write(WebSocketFrame.copy(frame));
write(WebSocketFrame.copy(frame).setMasked(false));
}
catch (IOException e)
{