JSR-356: adding WebSocketConfiguration and reworking ServerContainer init
This commit is contained in:
parent
cab4826c08
commit
c91c3f2f60
|
@ -70,9 +70,12 @@ public class Decoders
|
|||
Objects.requireNonNull(metadataFactory,"DecoderMetadataFactory cannot be null");
|
||||
this.metadataFactory = metadataFactory;
|
||||
|
||||
for (Class<? extends Decoder> decoder : config.getDecoders())
|
||||
if (config != null)
|
||||
{
|
||||
addAllMetadata(decoder);
|
||||
for (Class<? extends Decoder> decoder : config.getDecoders())
|
||||
{
|
||||
addAllMetadata(decoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,6 +156,14 @@ public class Decoders
|
|||
throw new InvalidSignatureException("Unable to find appropriate Decoder for type: " + type);
|
||||
}
|
||||
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
for (DecoderWrapper decoder : decoderMap.values())
|
||||
{
|
||||
decoder.getDecoder().init(config);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Class<?>> keySet()
|
||||
{
|
||||
return decoderMap.keySet();
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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 javax.websocket.ContainerProvider;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
/**
|
||||
* Client {@link ContainerProvider} implementation
|
||||
*/
|
||||
public class JettyClientContainerProvider extends ContainerProvider
|
||||
{
|
||||
@Override
|
||||
protected WebSocketContainer getContainer()
|
||||
{
|
||||
ClientContainer container = new ClientContainer();
|
||||
container.start();
|
||||
return container;
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.LinkedList;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class JettyContainerProvider extends ContainerProvider
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyContainerProvider.class);
|
||||
private final WebSocketContainer websocketContainer;
|
||||
|
||||
public JettyContainerProvider()
|
||||
{
|
||||
// Holds the list of ContainerService implementations found.
|
||||
LinkedList<ContainerService> services = new LinkedList<ContainerService>();
|
||||
|
||||
for (ContainerService impl : ServiceLoader.load(ContainerService.class))
|
||||
{
|
||||
if (impl instanceof ClientContainer)
|
||||
{
|
||||
// Sort client impls last.
|
||||
services.addLast(impl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// All others first. (such as ServiceContainer impls)
|
||||
services.addFirst(impl);
|
||||
}
|
||||
}
|
||||
|
||||
if (services.size() <= 0)
|
||||
{
|
||||
LOG.warn("Found no {} in classloader",ContainerService.class.getName());
|
||||
websocketContainer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
int len = services.size();
|
||||
|
||||
str.append("Found ").append(len).append(" websocket container");
|
||||
if (len > 1)
|
||||
{
|
||||
str.append('s');
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
ContainerService service = services.get(i);
|
||||
str.append("\n [").append(i).append("] ").append(service.getClass().getName());
|
||||
}
|
||||
|
||||
LOG.debug(str.toString());
|
||||
}
|
||||
|
||||
// Use first one (in list)
|
||||
ContainerService chosen = services.getFirst();
|
||||
LOG.debug("Using WebSocketContainer: {}",chosen.getClass().getName());
|
||||
chosen.start();
|
||||
|
||||
websocketContainer = chosen;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebSocketContainer getContainer()
|
||||
{
|
||||
return websocketContainer;
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ import java.util.HashSet;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -42,20 +43,21 @@ public class MessageHandlers
|
|||
/**
|
||||
* Factory for MessageHandlerMetadata instances.
|
||||
*/
|
||||
private MessageHandlerMetadataFactory factory;
|
||||
private final MessageHandlerMetadataFactory factory;
|
||||
/**
|
||||
* Array of MessageHandlerWrappers, indexed by {@link MessageType#ordinal()}
|
||||
*/
|
||||
private final MessageHandlerWrapper wrappers[];
|
||||
|
||||
public MessageHandlers()
|
||||
public MessageHandlers(MessageHandlerMetadataFactory factory)
|
||||
{
|
||||
Objects.requireNonNull(factory,"MessageHandlerMetadataFactory cannot be null");
|
||||
this.factory = factory;
|
||||
this.wrappers = new MessageHandlerWrapper[MessageType.values().length];
|
||||
}
|
||||
|
||||
public void add(MessageHandler handler)
|
||||
{
|
||||
assertFactoryDefined();
|
||||
Objects.requireNonNull(handler,"MessageHandler cannot be null");
|
||||
|
||||
synchronized (wrappers)
|
||||
|
@ -89,19 +91,6 @@ public class MessageHandlers
|
|||
}
|
||||
}
|
||||
|
||||
private void assertFactoryDefined()
|
||||
{
|
||||
if (this.factory == null)
|
||||
{
|
||||
throw new IllegalStateException("MessageHandlerMetadataFactory has not been set");
|
||||
}
|
||||
}
|
||||
|
||||
public MessageHandlerMetadataFactory getFactory()
|
||||
{
|
||||
return factory;
|
||||
}
|
||||
|
||||
public Set<MessageHandler> getUnmodifiableHandlerSet()
|
||||
{
|
||||
Set<MessageHandler> ret = new HashSet<>();
|
||||
|
@ -127,8 +116,6 @@ public class MessageHandlers
|
|||
|
||||
public void remove(MessageHandler handler)
|
||||
{
|
||||
assertFactoryDefined();
|
||||
|
||||
try
|
||||
{
|
||||
for (MessageHandlerMetadata metadata : factory.getMetadata(handler.getClass()))
|
||||
|
@ -141,9 +128,4 @@ public class MessageHandlers
|
|||
LOG.warn("Unable to identify MessageHandler: " + handler.getClass().getName(),e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFactory(MessageHandlerMetadataFactory factory)
|
||||
{
|
||||
this.factory = factory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.jsr356.annotations;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
@ -37,16 +38,21 @@ public class JsrParamIdBinary extends JsrParamIdOnMessage implements IJsrParamId
|
|||
@Override
|
||||
public boolean process(Param param, JsrCallable callable) throws InvalidSignatureException
|
||||
{
|
||||
Class<?> type = param.type;
|
||||
// Session parameter (optional)
|
||||
if (param.type.isAssignableFrom(Session.class))
|
||||
{
|
||||
param.bind(Role.SESSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.isAssignableFrom(ByteBuffer.class))
|
||||
if (param.type.isAssignableFrom(ByteBuffer.class))
|
||||
{
|
||||
param.bind(Role.MESSAGE_BINARY);
|
||||
callable.setDecoder(ByteBufferDecoder.INSTANCE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (type.isAssignableFrom(byte[].class))
|
||||
if (param.type.isAssignableFrom(byte[].class))
|
||||
{
|
||||
param.bind(Role.MESSAGE_BINARY);
|
||||
callable.setDecoder(ByteArrayDecoder.INSTANCE);
|
||||
|
@ -54,7 +60,7 @@ public class JsrParamIdBinary extends JsrParamIdOnMessage implements IJsrParamId
|
|||
}
|
||||
|
||||
// Boolean (for indicating partial message support)
|
||||
if (type.isAssignableFrom(Boolean.TYPE))
|
||||
if (param.type.isAssignableFrom(Boolean.TYPE))
|
||||
{
|
||||
param.bind(Role.MESSAGE_PARTIAL_FLAG);
|
||||
return true;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.annotations;
|
||||
|
||||
import javax.websocket.PongMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
@ -31,6 +32,13 @@ public class JsrParamIdPong extends JsrParamIdOnMessage implements IJsrParamId
|
|||
@Override
|
||||
public boolean process(Param param, JsrCallable callable) throws InvalidSignatureException
|
||||
{
|
||||
// Session parameter (optional)
|
||||
if (param.type.isAssignableFrom(Session.class))
|
||||
{
|
||||
param.bind(Role.SESSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (param.type.isAssignableFrom(PongMessage.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.annotations;
|
||||
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
@ -42,6 +43,13 @@ public class JsrParamIdText extends JsrParamIdOnMessage implements IJsrParamId
|
|||
@Override
|
||||
public boolean process(Param param, JsrCallable callable) throws InvalidSignatureException
|
||||
{
|
||||
// Session parameter (optional)
|
||||
if (param.type.isAssignableFrom(Session.class))
|
||||
{
|
||||
param.bind(Role.SESSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
// String for whole message
|
||||
if (param.type.isAssignableFrom(String.class))
|
||||
{
|
||||
|
|
|
@ -26,12 +26,14 @@ import java.nio.ByteBuffer;
|
|||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCode;
|
||||
import javax.websocket.CloseReason.CloseCodes;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
|
@ -39,16 +41,23 @@ import org.eclipse.jetty.websocket.common.WebSocketSession;
|
|||
import org.eclipse.jetty.websocket.common.events.AbstractEventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageAppender;
|
||||
import org.eclipse.jetty.websocket.jsr356.ContainerService;
|
||||
import org.eclipse.jetty.websocket.jsr356.Decoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlers;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.BinaryPartialMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.BinaryStreamMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.BinaryWholeMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadataFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.TextPartialMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.TextStreamMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.TextWholeMessage;
|
||||
|
||||
/**
|
||||
* EventDriver for websocket that extend from {@link javax.websocket.Endpoint}
|
||||
*/
|
||||
public class JsrEndpointEventDriver extends AbstractEventDriver implements EventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JsrEndpointEventDriver.class);
|
||||
|
@ -82,6 +91,11 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
if (activeMessage == null)
|
||||
{
|
||||
MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
if (wrapper == null)
|
||||
{
|
||||
LOG.debug("No BINARY MessageHandler declared");
|
||||
return;
|
||||
}
|
||||
if (wrapper.wantsPartialMessages())
|
||||
{
|
||||
activeMessage = new BinaryPartialMessage(wrapper);
|
||||
|
@ -170,6 +184,11 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
if (activeMessage == null)
|
||||
{
|
||||
MessageHandlerWrapper wrapper = jsrsession.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
if (wrapper == null)
|
||||
{
|
||||
LOG.debug("No TEXT MessageHandler declared");
|
||||
return;
|
||||
}
|
||||
if (wrapper.wantsPartialMessages())
|
||||
{
|
||||
activeMessage = new TextPartialMessage(wrapper);
|
||||
|
@ -204,14 +223,29 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
{
|
||||
// Cast should be safe, as it was created by JsrSessionFactory
|
||||
this.jsrsession = (JsrSession)session;
|
||||
// TODO: Create Decoders (Facade)
|
||||
// TODO: Create MessageHandlers (Facade)
|
||||
|
||||
try
|
||||
{
|
||||
// Create Decoders
|
||||
ContainerService container = (ContainerService)jsrsession.getContainer();
|
||||
Decoders decoders = new Decoders(container.getDecoderMetadataFactory(),endpointconfig);
|
||||
jsrsession.setDecodersFacade(decoders);
|
||||
|
||||
// Create MessageHandlers
|
||||
MessageHandlerMetadataFactory metadataFactory = new MessageHandlerMetadataFactory(decoders);
|
||||
MessageHandlers messageHandlers = new MessageHandlers(metadataFactory);
|
||||
jsrsession.setMessageHandlerFacade(messageHandlers);
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
|
||||
// Allow end-user socket to adjust configuration
|
||||
super.openSession(session);
|
||||
|
||||
// TODO: Initialize Decoders
|
||||
// TODO: Initialize MessageHandlers
|
||||
// Initialize Decoders
|
||||
jsrsession.getDecodersFacade().init(endpointconfig);
|
||||
}
|
||||
|
||||
public void setEndpointconfig(EndpointConfig endpointconfig)
|
||||
|
|
|
@ -1 +1 @@
|
|||
org.eclipse.jetty.websocket.jsr356.JettyContainerProvider
|
||||
org.eclipse.jetty.websocket.jsr356.JettyClientContainerProvider
|
|
@ -1 +0,0 @@
|
|||
org.eclipse.jetty.websocket.jsr356.ClientContainer
|
|
@ -27,6 +27,8 @@ import javax.websocket.Endpoint;
|
|||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
@ -34,6 +36,7 @@ import org.junit.Assert;
|
|||
*/
|
||||
public class EndpointEchoClient extends Endpoint
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(EndpointEchoClient.class);
|
||||
private Session session = null;
|
||||
private CloseReason close = null;
|
||||
public EchoCaptureHandler textCapture = new EchoCaptureHandler();
|
||||
|
@ -46,6 +49,7 @@ public class EndpointEchoClient extends Endpoint
|
|||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config)
|
||||
{
|
||||
LOG.debug("onOpen({}, {})",session,config);
|
||||
this.session = session;
|
||||
Assert.assertThat("Session",session,notNullValue());
|
||||
Assert.assertThat("EndpointConfig",config,notNullValue());
|
||||
|
|
|
@ -50,8 +50,7 @@ public class MessageHandlersTest
|
|||
@Test
|
||||
public void testGetBinaryHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers();
|
||||
mhs.setFactory(factory);
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
mhs.add(new ByteBufferPartialHandler());
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.BINARY);
|
||||
Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteBufferPartialHandler.class));
|
||||
|
@ -60,8 +59,7 @@ public class MessageHandlersTest
|
|||
@Test
|
||||
public void testGetBothHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers();
|
||||
mhs.setFactory(factory);
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
mhs.add(new StringWholeHandler());
|
||||
mhs.add(new ByteArrayWholeHandler());
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.TEXT);
|
||||
|
@ -73,25 +71,16 @@ public class MessageHandlersTest
|
|||
@Test
|
||||
public void testGetTextHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers();
|
||||
mhs.setFactory(factory);
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
mhs.add(new StringWholeHandler());
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.TEXT);
|
||||
Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testNoFactoryAdd()
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers();
|
||||
mhs.add(new ByteBufferPartialHandler());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTextHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers();
|
||||
mhs.setFactory(factory);
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
MessageHandler oldText = new StringWholeHandler();
|
||||
mhs.add(oldText); // add a TEXT handler
|
||||
mhs.add(new ByteArrayWholeHandler()); // add BINARY handler
|
||||
|
|
|
@ -46,6 +46,36 @@ public class JettyServerEndpointConfig implements ServerEndpointConfig
|
|||
private List<Extension> extensions;
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public JettyServerEndpointConfig(Class<?> endpointClass, ServerEndpoint anno) throws DeploymentException
|
||||
{
|
||||
this(endpointClass,anno.value());
|
||||
addAll(anno.decoders(),this.decoders);
|
||||
addAll(anno.encoders(),this.encoders);
|
||||
addAll(anno.subprotocols(),this.subprotocols);
|
||||
// no extensions declared in annotation
|
||||
// no userProperties in annotation
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
this.configurator = BaseConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ServerEndpoint.configurator() of ");
|
||||
err.append(anno.configurator().getName());
|
||||
err.append(" defined as annotation in ");
|
||||
err.append(anno.getClass().getName());
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JettyServerEndpointConfig(Class<?> endpointClass, String path)
|
||||
{
|
||||
this.endpointClass = endpointClass;
|
||||
|
@ -95,36 +125,6 @@ public class JettyServerEndpointConfig implements ServerEndpointConfig
|
|||
}
|
||||
}
|
||||
|
||||
public JettyServerEndpointConfig(ServerEndpoint anno) throws DeploymentException
|
||||
{
|
||||
this(anno.getClass(),anno.value());
|
||||
addAll(anno.decoders(),this.decoders);
|
||||
addAll(anno.encoders(),this.encoders);
|
||||
addAll(anno.subprotocols(),this.subprotocols);
|
||||
// no extensions declared in annotation
|
||||
// no userProperties in annotation
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
this.configurator = BaseConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ServerEndpoint.configurator() of ");
|
||||
err.append(anno.configurator().getName());
|
||||
err.append(" defined as annotation in ");
|
||||
err.append(anno.getClass().getName());
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void addAll(T[] arr, List<T> lst)
|
||||
{
|
||||
if (arr == null)
|
||||
|
@ -184,4 +184,26 @@ public class JettyServerEndpointConfig implements ServerEndpointConfig
|
|||
{
|
||||
return userProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("JettyServerEndpointConfig [endpointClass=");
|
||||
builder.append(endpointClass);
|
||||
builder.append(", path=");
|
||||
builder.append(path);
|
||||
builder.append(", configurator=");
|
||||
builder.append(configurator);
|
||||
builder.append(", decoders=");
|
||||
builder.append(decoders);
|
||||
builder.append(", encoders=");
|
||||
builder.append(encoders);
|
||||
builder.append(", subprotocols=");
|
||||
builder.append(subprotocols);
|
||||
builder.append(", extensions=");
|
||||
builder.append(extensions);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,35 +26,56 @@ import javax.websocket.server.HandshakeRequest;
|
|||
import javax.websocket.server.ServerEndpointConfig;
|
||||
import javax.websocket.server.ServerEndpointConfig.Configurator;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class JettyServerEndpointConfigurator extends Configurator
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyServerEndpointConfigurator.class);
|
||||
|
||||
@Override
|
||||
public boolean checkOrigin(String originHeaderValue)
|
||||
{
|
||||
return super.checkOrigin(originHeaderValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
|
||||
{
|
||||
return super.getEndpointInstance(endpointClass);
|
||||
LOG.debug(".getEndpointInstance({})",endpointClass);
|
||||
try
|
||||
{
|
||||
return endpointClass.newInstance();
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new InstantiationException(String.format("%s: %s",e.getClass().getName(),e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
|
||||
{
|
||||
return super.getNegotiatedExtensions(installed,requested);
|
||||
/* do nothing */
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
|
||||
{
|
||||
return super.getNegotiatedSubprotocol(supported,requested);
|
||||
for (String possible : requested)
|
||||
{
|
||||
if (supported.contains(possible))
|
||||
{
|
||||
return possible;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
|
||||
{
|
||||
super.modifyHandshake(sec,request,response);
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,9 +76,10 @@ public class JsrCreator implements WebSocketCreator
|
|||
// create endpoint class
|
||||
try
|
||||
{
|
||||
return config.getEndpointClass().newInstance();
|
||||
Class<?> endpointClass = config.getEndpointClass();
|
||||
return config.getConfigurator().getEndpointInstance(endpointClass);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
LOG.debug("Unable to create websocket: " + config.getEndpointClass().getName(),e);
|
||||
return null;
|
||||
|
|
|
@ -50,7 +50,7 @@ public class JsrServerMetadata extends JsrMetadata<ServerEndpoint>
|
|||
}
|
||||
|
||||
this.endpoint = anno;
|
||||
this.config = new JettyServerEndpointConfig(anno);
|
||||
this.config = new JettyServerEndpointConfig(websocket,anno);
|
||||
this.decoders = new Decoders(container.getDecoderMetadataFactory(),config);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,54 +18,37 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSessionFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrEndpointImpl;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec;
|
||||
import org.eclipse.jetty.websocket.server.MappedWebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
|
||||
public class ServerContainer extends ClientContainer implements javax.websocket.server.ServerContainer
|
||||
public class ServerContainer extends ClientContainer implements javax.websocket.server.ServerContainer, WebSocketServerFactory.Listener
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ServerContainer.class);
|
||||
|
||||
public static ServerContainer getInstance()
|
||||
public static ServerContainer get(WebAppContext context)
|
||||
{
|
||||
return (ServerContainer)ContainerProvider.getWebSocketContainer();
|
||||
return (ServerContainer)context.getAttribute(WebSocketConfiguration.JAVAX_WEBSOCKET_SERVER_CONTAINER);
|
||||
}
|
||||
private ConcurrentHashMap<Class<?>, JsrServerMetadata> endpointServerMetadataCache = new ConcurrentHashMap<>();
|
||||
private MappedWebSocketCreator mappedCreator;
|
||||
|
||||
public ServerContainer()
|
||||
private final MappedWebSocketCreator mappedCreator;
|
||||
private WebSocketServerFactory webSocketServletFactory;
|
||||
private ConcurrentHashMap<Class<?>, JsrServerMetadata> endpointServerMetadataCache = new ConcurrentHashMap<>();
|
||||
|
||||
public ServerContainer(MappedWebSocketCreator creator)
|
||||
{
|
||||
super();
|
||||
WebAppContext webapp = WebAppContext.getCurrentWebAppContext();
|
||||
if (webapp != null)
|
||||
{
|
||||
WebSocketUpgradeFilter filter = new WebSocketUpgradeFilter();
|
||||
FilterHolder fholder = new FilterHolder(filter);
|
||||
fholder.setName("Jetty_WebSocketUpgradeFilter");
|
||||
fholder.setDisplayName("WebSocket Upgrade Filter");
|
||||
String pathSpec = "/*";
|
||||
webapp.addFilter(fholder,pathSpec,EnumSet.of(DispatcherType.REQUEST));
|
||||
LOG.debug("Adding {} mapped to {} to {}",filter,pathSpec,webapp);
|
||||
mappedCreator = filter;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("No active WebAppContext detected");
|
||||
}
|
||||
this.mappedCreator = creator;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,11 +70,6 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
mappedCreator.addMapping(new WebSocketPathSpec(config.getPath()),creator);
|
||||
}
|
||||
|
||||
public void addMappedCreator(MappedWebSocketCreator mappedCreator)
|
||||
{
|
||||
this.mappedCreator = mappedCreator;
|
||||
}
|
||||
|
||||
public JsrServerMetadata getServerEndpointMetadata(Class<?> endpointClass) throws DeploymentException
|
||||
{
|
||||
JsrServerMetadata basemetadata = endpointServerMetadataCache.get(endpointClass);
|
||||
|
@ -105,4 +83,25 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
|
||||
return basemetadata;
|
||||
}
|
||||
|
||||
public WebSocketServletFactory getWebSocketServletFactory()
|
||||
{
|
||||
return webSocketServletFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketServerFactoryStarted(WebSocketServerFactory factory)
|
||||
{
|
||||
this.webSocketServletFactory = factory;
|
||||
EventDriverFactory eventDriverFactory = this.webSocketServletFactory.getEventDriverFactory();
|
||||
eventDriverFactory.addImplementation(new JsrServerEndpointImpl(this));
|
||||
eventDriverFactory.addImplementation(new JsrEndpointImpl());
|
||||
this.webSocketServletFactory.setSessionFactory(new JsrSessionFactory(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketServerFactoryStopped(WebSocketServerFactory factory)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
|
@ -58,7 +57,7 @@ public class ServerEndpointAnnotation extends DiscoveredAnnotation
|
|||
String path = annotation.value();
|
||||
LOG.info("Got path: \"{}\"",path);
|
||||
|
||||
ServerContainer container = (ServerContainer)ContainerProvider.getWebSocketContainer();
|
||||
ServerContainer container = ServerContainer.get(_context);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.AbstractConfiguration;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
|
||||
/**
|
||||
* WebSocket Server Configuration component
|
||||
*/
|
||||
public class WebSocketConfiguration extends AbstractConfiguration
|
||||
{
|
||||
public static final String JAVAX_WEBSOCKET_SERVER_CONTAINER = "javax.websocket.server.ServerContainer";
|
||||
private static final Logger LOG = Log.getLogger(WebSocketConfiguration.class);
|
||||
|
||||
@Override
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
{
|
||||
WebSocketUpgradeFilter filter = new WebSocketUpgradeFilter();
|
||||
FilterHolder fholder = new FilterHolder(filter);
|
||||
fholder.setName("Jetty_WebSocketUpgradeFilter");
|
||||
fholder.setDisplayName("WebSocket Upgrade Filter");
|
||||
String pathSpec = "/*";
|
||||
context.addFilter(fholder,pathSpec,EnumSet.of(DispatcherType.REQUEST));
|
||||
LOG.debug("Adding {} mapped to {} to {}",filter,pathSpec,context);
|
||||
|
||||
ServerContainer container = new ServerContainer(filter);
|
||||
filter.setWebSocketServerFactoryListener(container);
|
||||
context.setAttribute(JAVAX_WEBSOCKET_SERVER_CONTAINER,container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
// Add the annotation scanning handlers (if annotation scanning enabled)
|
||||
for (Configuration config : context.getConfigurations())
|
||||
{
|
||||
if (config instanceof AnnotationConfiguration)
|
||||
{
|
||||
AnnotationConfiguration annocfg = (AnnotationConfiguration)config;
|
||||
annocfg.addDiscoverableAnnotationHandler(new ServerEndpointAnnotationHandler(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
org.eclipse.jetty.websocket.jsr356.server.ServerContainer
|
|
@ -23,16 +23,8 @@ import java.util.Queue;
|
|||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
|
||||
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.FragmentConfiguration;
|
||||
import org.eclipse.jetty.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.webapp.WebInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebXmlConfiguration;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoSocket;
|
||||
|
@ -61,27 +53,15 @@ public class BasicAnnotatedTest
|
|||
URI uri = wsb.getServerBaseURI();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
AnnotationConfiguration annocfg = new AnnotationConfiguration();
|
||||
annocfg.addDiscoverableAnnotationHandler(new ServerEndpointAnnotationHandler(webapp));
|
||||
// @formatter:off
|
||||
webapp.setConfigurations(new Configuration[] {
|
||||
annocfg,
|
||||
new WebXmlConfiguration(),
|
||||
new WebInfConfiguration(),
|
||||
new PlusConfiguration(),
|
||||
new MetaInfConfiguration(),
|
||||
new FragmentConfiguration(),
|
||||
new EnvConfiguration()});
|
||||
// @formatter:on
|
||||
wsb.deployWebapp(webapp);
|
||||
// wsb.dump();
|
||||
wsb.dump();
|
||||
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
JettyEchoSocket clientEcho = new JettyEchoSocket();
|
||||
Future<Session> foo = client.connect(clientEcho,uri.resolve("/echo"));
|
||||
Future<Session> foo = client.connect(clientEcho,uri.resolve("echo"));
|
||||
// wait for connect
|
||||
foo.get(1,TimeUnit.SECONDS);
|
||||
clientEcho.sendMessage("Hello World");
|
||||
|
|
|
@ -61,7 +61,6 @@ public class BasicEndpointTest
|
|||
URI uri = wsb.getServerBaseURI();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
// default webapp configuration used (no annotation scanning)
|
||||
wsb.deployWebapp(webapp);
|
||||
wsb.dump();
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import org.eclipse.jetty.websocket.server.MappedWebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
|
||||
import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
|
||||
public class DummyCreator implements MappedWebSocketCreator
|
||||
{
|
||||
@Override
|
||||
public void addMapping(PathSpec spec, WebSocketCreator creator)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathMappings<WebSocketCreator> getMappings()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -46,6 +46,7 @@ import org.eclipse.jetty.websocket.jsr356.server.samples.BasicOpenSessionSocket;
|
|||
import org.eclipse.jetty.websocket.jsr356.server.samples.BasicOpenSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.BasicPongMessageSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.BasicTextMessageStringSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.StatelessTextMessageStringSocket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -81,7 +82,7 @@ public class ServerAnnotatedEndpointScanner_GoodSignaturesTest
|
|||
}
|
||||
}
|
||||
|
||||
private static ServerContainer container = new ServerContainer();
|
||||
private static ServerContainer container = new ServerContainer(new DummyCreator());
|
||||
|
||||
@Parameters
|
||||
public static Collection<Case[]> data() throws Exception
|
||||
|
@ -111,6 +112,7 @@ public class ServerAnnotatedEndpointScanner_GoodSignaturesTest
|
|||
Case.add(data, BasicErrorThrowableSessionSocket.class, fError, Throwable.class, Session.class);
|
||||
// -- Text Events
|
||||
Case.add(data, BasicTextMessageStringSocket.class, fText, String.class);
|
||||
Case.add(data, StatelessTextMessageStringSocket.class, fText, Session.class, String.class);
|
||||
// -- Binary Events
|
||||
Case.add(data, BasicBinaryMessageByteBufferSocket.class, fBinary, ByteBuffer.class);
|
||||
// -- Pong Events
|
||||
|
|
|
@ -55,7 +55,7 @@ public class ServerAnnotatedEndpointScanner_InvalidSignaturesTest
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(ServerAnnotatedEndpointScanner_InvalidSignaturesTest.class);
|
||||
|
||||
private static ServerContainer container = new ServerContainer();
|
||||
private static ServerContainer container = new ServerContainer(new DummyCreator());
|
||||
|
||||
@Parameters
|
||||
public static Collection<Class<?>[]> data()
|
||||
|
|
|
@ -25,6 +25,9 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.plus.webapp.EnvConfiguration;
|
||||
import org.eclipse.jetty.plus.webapp.PlusConfiguration;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
|
@ -36,7 +39,12 @@ import org.eclipse.jetty.toolchain.test.OS;
|
|||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.Configuration;
|
||||
import org.eclipse.jetty.webapp.FragmentConfiguration;
|
||||
import org.eclipse.jetty.webapp.MetaInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.webapp.WebInfConfiguration;
|
||||
import org.eclipse.jetty.webapp.WebXmlConfiguration;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
@ -98,6 +106,19 @@ public class WSServer
|
|||
WebAppContext context = new WebAppContext();
|
||||
context.setContextPath(this.contextPath);
|
||||
context.setWar(this.contextDir.getAbsolutePath());
|
||||
|
||||
// @formatter:off
|
||||
context.setConfigurations(new Configuration[] {
|
||||
new WebSocketConfiguration(),
|
||||
new AnnotationConfiguration(),
|
||||
new WebXmlConfiguration(),
|
||||
new WebInfConfiguration(),
|
||||
new PlusConfiguration(),
|
||||
new MetaInfConfiguration(),
|
||||
new FragmentConfiguration(),
|
||||
new EnvConfiguration()});
|
||||
// @formatter:on
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
@ -146,7 +167,7 @@ public class WSServer
|
|||
host = "localhost";
|
||||
}
|
||||
int port = connector.getLocalPort();
|
||||
serverUri = new URI(String.format("ws://%s:%d/",host,port));
|
||||
serverUri = new URI(String.format("ws://%s:%d%s/",host,port,contextPath));
|
||||
LOG.debug("Server started on {}",serverUri);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server.samples;
|
||||
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.server.TrackingSocket;
|
||||
|
||||
@ServerEndpoint(value = "/stateless")
|
||||
public class StatelessTextMessageStringSocket extends TrackingSocket
|
||||
{
|
||||
@OnMessage
|
||||
public void onText(Session session, String message)
|
||||
{
|
||||
addEvent("onText(%s,%s)",session,message);
|
||||
dataLatch.countDown();
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -62,8 +63,14 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
|||
*/
|
||||
public class WebSocketServerFactory extends ContainerLifeCycle implements WebSocketCreator, WebSocketServletFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
|
||||
public static interface Listener
|
||||
{
|
||||
void onWebSocketServerFactoryStarted(WebSocketServerFactory factory);
|
||||
|
||||
void onWebSocketServerFactoryStopped(WebSocketServerFactory factory);
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
|
||||
private static final ThreadLocal<UpgradeContext> ACTIVE_CONTEXT = new ThreadLocal<>();
|
||||
|
||||
public static UpgradeContext getActiveUpgradeContext()
|
||||
|
@ -81,15 +88,16 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
handshakes.put(HandshakeRFC6455.VERSION,new HandshakeRFC6455());
|
||||
}
|
||||
|
||||
private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
|
||||
/**
|
||||
* Have the factory maintain 1 and only 1 scheduler. All connections share this scheduler.
|
||||
*/
|
||||
private final Scheduler scheduler = new ScheduledExecutorScheduler();
|
||||
private final Queue<WebSocketSession> sessions = new ConcurrentLinkedQueue<>();
|
||||
private final String supportedVersions;
|
||||
private final WebSocketPolicy basePolicy;
|
||||
private final EventDriverFactory eventDriverFactory;
|
||||
private final WebSocketExtensionFactory extensionFactory;
|
||||
private List<WebSocketServerFactory.Listener> listeners = new ArrayList<>();
|
||||
private SessionFactory sessionFactory;
|
||||
private WebSocketCreator creator;
|
||||
private List<Class<?>> registeredSocketClasses;
|
||||
|
@ -177,6 +185,11 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
return upgrade(sockreq,sockresp,driver);
|
||||
}
|
||||
|
||||
public void addListener(WebSocketServerFactory.Listener listener)
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup()
|
||||
{
|
||||
|
@ -232,10 +245,24 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
for (WebSocketServerFactory.Listener listener : listeners)
|
||||
{
|
||||
listener.onWebSocketServerFactoryStarted(this);
|
||||
}
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws Exception
|
||||
{
|
||||
closeAllConnections();
|
||||
for (WebSocketServerFactory.Listener listener : listeners)
|
||||
{
|
||||
listener.onWebSocketServerFactoryStopped(this);
|
||||
}
|
||||
super.doStop();
|
||||
}
|
||||
|
||||
|
@ -256,6 +283,11 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
return extensionFactory;
|
||||
}
|
||||
|
||||
public Collection<WebSocketServerFactory.Listener> getListeners()
|
||||
{
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
|
@ -336,17 +368,17 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
return protocols;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.jetty.websocket.server.WebSocketServletFactory#register(java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public void register(Class<?> websocketPojo)
|
||||
{
|
||||
registeredSocketClasses.add(websocketPojo);
|
||||
}
|
||||
|
||||
public void removeListener(WebSocketServerFactory.Listener listener)
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public boolean sessionClosed(WebSocketSession session)
|
||||
{
|
||||
return isRunning() && sessions.remove(session);
|
||||
|
|
|
@ -41,7 +41,6 @@ import org.eclipse.jetty.websocket.server.pathmap.PathMappings;
|
|||
import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource;
|
||||
import org.eclipse.jetty.websocket.server.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
|
||||
/**
|
||||
* Inline Servlet Filter to capture WebSocket upgrade requests and perform path mappings to {@link WebSocketCreator} objects.
|
||||
|
@ -51,7 +50,8 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketUpgradeFilter.class);
|
||||
private PathMappings<WebSocketCreator> pathmap = new PathMappings<>();
|
||||
private WebSocketServletFactory factory;
|
||||
private WebSocketServerFactory factory;
|
||||
private WebSocketServerFactory.Listener listener;
|
||||
|
||||
@Override
|
||||
public void addMapping(PathSpec spec, WebSocketCreator creator)
|
||||
|
@ -76,21 +76,26 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
|
|||
return;
|
||||
}
|
||||
|
||||
if ((request instanceof HttpServletRequest) && (request instanceof HttpServletResponse))
|
||||
LOG.debug("doFilter({})",request);
|
||||
|
||||
if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse))
|
||||
{
|
||||
HttpServletRequest httpreq = (HttpServletRequest)request;
|
||||
HttpServletResponse httpresp = (HttpServletResponse)response;
|
||||
String target = httpreq.getPathInfo();
|
||||
String target = httpreq.getServletPath();
|
||||
LOG.debug("target = [{}]",target);
|
||||
|
||||
if (factory.isUpgradeRequest(httpreq,httpresp))
|
||||
{
|
||||
MappedResource<WebSocketCreator> resource = pathmap.getMatch(target);
|
||||
if (resource == null)
|
||||
{
|
||||
LOG.debug("WebSocket Upgrade on {} has no associated endpoint",target);
|
||||
// no match.
|
||||
httpresp.sendError(HttpServletResponse.SC_NOT_FOUND,"No websocket endpoint matching path: " + target);
|
||||
return;
|
||||
}
|
||||
LOG.debug("WebSocket Upgrade detected on {} for endpoint {}",target,resource);
|
||||
|
||||
WebSocketCreator creator = resource.getResource();
|
||||
|
||||
|
@ -171,7 +176,8 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
|
|||
policy.setInputBufferSize(Integer.parseInt(max));
|
||||
}
|
||||
|
||||
factory = WebSocketServletFactory.Loader.create(policy);
|
||||
factory = new WebSocketServerFactory(policy);
|
||||
factory.addListener(this.listener);
|
||||
factory.init();
|
||||
}
|
||||
catch (Exception x)
|
||||
|
@ -180,6 +186,11 @@ public class WebSocketUpgradeFilter implements Filter, MappedWebSocketCreator, D
|
|||
}
|
||||
}
|
||||
|
||||
public void setWebSocketServerFactoryListener(WebSocketServerFactory.Listener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue