JSR-356 adding support for ClientEndpointConfig.Configurator

This commit is contained in:
Joakim Erdfelt 2013-05-22 15:15:05 -07:00
parent 598ecd7d7f
commit 97854b6c5b
10 changed files with 324 additions and 3 deletions

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.client.io.UpgradeListener;
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
import org.eclipse.jetty.websocket.jsr356.endpoints.ConfiguredEndpoint;
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrClientMetadata;
@ -64,6 +65,8 @@ public class ClientContainer implements ContainerService
}
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(websocket,cec);
ClientUpgradeRequest req = new ClientUpgradeRequest();
UpgradeListener upgradeListener = null;
if (cec != null)
{
for (Extension ext : cec.getExtensions())
@ -75,8 +78,14 @@ public class ClientContainer implements ContainerService
{
req.setSubProtocols(config.getPreferredSubprotocols());
}
if (cec.getConfigurator() != null)
{
upgradeListener = new JsrUpgradeListener(cec.getConfigurator());
}
}
Future<org.eclipse.jetty.websocket.api.Session> futSess = client.connect(endpoint,path,req);
Future<org.eclipse.jetty.websocket.api.Session> futSess = client.connect(endpoint,path,req,upgradeListener);
try
{
return (JsrSession)futSess.get();

View File

@ -0,0 +1,42 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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 java.util.List;
import java.util.Map;
import javax.websocket.HandshakeResponse;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
public class JsrHandshakeResponse implements HandshakeResponse
{
private final Map<String, List<String>> headers;
public JsrHandshakeResponse(UpgradeResponse response)
{
this.headers = response.getHeaders();
}
@Override
public Map<String, List<String>> getHeaders()
{
return this.headers;
}
}

View File

@ -0,0 +1,63 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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 java.util.List;
import java.util.Map;
import javax.websocket.ClientEndpointConfig.Configurator;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
import org.eclipse.jetty.websocket.client.io.UpgradeListener;
public class JsrUpgradeListener implements UpgradeListener
{
private Configurator configurator;
public JsrUpgradeListener(Configurator configurator)
{
this.configurator = configurator;
}
@Override
public void onHandshakeRequest(UpgradeRequest request)
{
if (configurator == null)
{
return;
}
Map<String, List<String>> headers = request.getHeaders();
configurator.beforeRequest(headers);
request.setHeaders(headers);
}
@Override
public void onHandshakeResponse(UpgradeResponse response)
{
if (configurator == null)
{
return;
}
JsrHandshakeResponse hr = new JsrHandshakeResponse(response);
configurator.afterResponse(hr);
}
}

View File

@ -0,0 +1,124 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.net.URI;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.ContainerProvider;
import javax.websocket.HandshakeResponse;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Tests of {@link ClientEndpointConfig.Configurator}
*/
public class ConfiguratorTest
{
public class TrackingConfigurator extends ClientEndpointConfig.Configurator
{
public HandshakeResponse response;
public Map<String, List<String>> request;
@Override
public void afterResponse(HandshakeResponse hr)
{
this.response = hr;
}
@Override
public void beforeRequest(Map<String, List<String>> headers)
{
this.request = headers;
}
}
private static Server server;
private static EchoHandler handler;
private static URI serverUri;
@BeforeClass
public static void startServer() throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
handler = new EchoHandler();
ContextHandler context = new ContextHandler();
context.setContextPath("/");
context.setHandler(handler);
server.setHandler(context);
// Start Server
server.start();
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("ws://%s:%d/",host,port));
}
@AfterClass
public static void stopServer()
{
try
{
server.stop();
}
catch (Exception e)
{
e.printStackTrace(System.err);
}
}
@Test
public void testEndpointHandshakeInfo() throws Exception
{
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
EndpointEchoClient echoer = new EndpointEchoClient();
ClientEndpointConfig.Builder cfgbldr = ClientEndpointConfig.Builder.create();
TrackingConfigurator configurator = new TrackingConfigurator();
cfgbldr.configurator(configurator);
ClientEndpointConfig config = cfgbldr.build();
Session session = container.connectToServer(echoer,config,serverUri);
session.getBasicRemote().sendText("Echo");
echoer.textCapture.messageQueue.awaitMessages(1,1000,TimeUnit.MILLISECONDS);
Assert.assertThat("configurator.request",configurator.request,notNullValue());
Assert.assertThat("configurator.response",configurator.response,notNullValue());
}
}

View File

@ -75,6 +75,11 @@ public class UpgradeRequest
}
}
public void clearHeaders()
{
headers.clear();
}
public List<HttpCookie> getCookies()
{
return cookies;
@ -242,6 +247,18 @@ public class UpgradeRequest
setHeader(name.toLowerCase(Locale.ENGLISH),values);
}
public void setHeaders(Map<String, List<String>> headers)
{
clearHeaders();
for (Map.Entry<String, List<String>> entry : headers.entrySet())
{
String name = entry.getKey();
List<String> values = entry.getValue();
setHeader(name,values);
}
}
public void setHttpVersion(String httpVersion)
{
this.httpVersion = httpVersion;

View File

@ -47,6 +47,7 @@ import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
import org.eclipse.jetty.websocket.client.io.ConnectPromise;
import org.eclipse.jetty.websocket.client.io.ConnectionManager;
import org.eclipse.jetty.websocket.client.io.UpgradeListener;
import org.eclipse.jetty.websocket.client.masks.Masker;
import org.eclipse.jetty.websocket.client.masks.RandomMasker;
import org.eclipse.jetty.websocket.common.SessionFactory;
@ -101,6 +102,11 @@ public class WebSocketClient extends ContainerLifeCycle
}
public Future<Session> connect(Object websocket, URI toUri, ClientUpgradeRequest request) throws IOException
{
return connect(websocket,toUri,request,null);
}
public Future<Session> connect(Object websocket, URI toUri, ClientUpgradeRequest request, UpgradeListener upgradeListener) throws IOException
{
if (!isStarted())
{
@ -163,6 +169,11 @@ public class WebSocketClient extends ContainerLifeCycle
// Create the appropriate (physical vs virtual) connection task
ConnectPromise promise = manager.connect(this,driver,request);
if (upgradeListener != null)
{
promise.setUpgradeListener(upgradeListener);
}
LOG.debug("Connect Promise: {}",promise);
// Execute the connection on the executor thread

View File

@ -36,6 +36,7 @@ public abstract class ConnectPromise extends FuturePromise<Session> implements R
private final EventDriver driver;
private final ClientUpgradeRequest request;
private final Masker masker;
private UpgradeListener upgradeListener;
private ClientUpgradeResponse response;
public ConnectPromise(WebSocketClient client, EventDriver driver, ClientUpgradeRequest request)
@ -81,11 +82,21 @@ public abstract class ConnectPromise extends FuturePromise<Session> implements R
return response;
}
public UpgradeListener getUpgradeListener()
{
return upgradeListener;
}
public void setResponse(ClientUpgradeResponse response)
{
this.response = response;
}
public void setUpgradeListener(UpgradeListener upgradeListener)
{
this.upgradeListener = upgradeListener;
}
public void succeeded(WebSocketSession session)
{
session.setUpgradeRequest(request);

View File

@ -203,7 +203,7 @@ public class ConnectionManager extends ContainerLifeCycle
return Collections.unmodifiableCollection(sessions);
}
private boolean isVirtualConnectionPossibleTo(String hostname)
public boolean isVirtualConnectionPossibleTo(String hostname)
{
// TODO Auto-generated method stub
return false;

View File

@ -61,6 +61,13 @@ public class UpgradeConnection extends AbstractConnection
{
URI uri = connectPromise.getRequest().getRequestURI();
request.setRequestURI(uri);
UpgradeListener handshakeListener = connectPromise.getUpgradeListener();
if (handshakeListener != null)
{
handshakeListener.onHandshakeRequest(request);
}
String rawRequest = request.generate();
ByteBuffer buf = BufferUtil.toBuffer(rawRequest,StringUtil.__UTF8_CHARSET);
@ -114,6 +121,12 @@ public class UpgradeConnection extends AbstractConnection
private void notifyConnect(ClientUpgradeResponse response)
{
connectPromise.setResponse(response);
UpgradeListener handshakeListener = connectPromise.getUpgradeListener();
if (handshakeListener != null)
{
handshakeListener.onHandshakeResponse(response);
}
}
@Override
@ -141,7 +154,6 @@ public class UpgradeConnection extends AbstractConnection
public void onOpen()
{
super.onOpen();
// TODO: handle timeout
getExecutor().execute(new SendUpgradeRequest());
}

View File

@ -0,0 +1,32 @@
//
// ========================================================================
// Copyright (c) 1995-2013 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.client.io;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.UpgradeResponse;
/**
* Listener for Handshake/Upgrade events.
*/
public interface UpgradeListener
{
public void onHandshakeRequest(UpgradeRequest request);
public void onHandshakeResponse(UpgradeResponse response);
}