453834 - CDI Support for WebSocket

+ Verifying ServletContextHandler behavior of Decorators
+ Marking old ServletContextHandler methods as deprecated
+ Updates to DecoratedObjectFactory
+ Removing customized weld scopes/context (for now)
+ Deferring JSR356 ServerContainer endpoint init
  till Container.doStart() to allow weld to init properly first
+ Removing JSR356 BasicServerEndpointConfigurator in favor
  of ContainerDefaultEndpointConfigurator
+ Only decorating server endpoints if they were created by
  ContainerDefaultEndpointConfigurator, all others are trusted
  to be complete and injected already.
This commit is contained in:
Joakim Erdfelt 2015-01-30 15:13:35 -07:00
parent e213c4488e
commit 87246263b8
28 changed files with 655 additions and 347 deletions

View File

@ -16,25 +16,22 @@
// ========================================================================
//
package org.eclipse.jetty.cdi.weld;
package org.eclipse.jetty.cdi.producers;
import java.util.Map;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import org.jboss.weld.context.bound.BoundRequest;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class WebSocketBoundRequest implements BoundRequest
/**
* CDI Producer of Jetty Logging instances.
*/
public class JettyLogFactory
{
@Override
public Map<String, Object> getRequestMap()
@Produces
public Logger createLogger(InjectionPoint injectionPoint)
{
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, Object> getSessionMap(boolean create)
{
// TODO Auto-generated method stub
return null;
return Log.getLogger(injectionPoint.getMember().getDeclaringClass());
}
}

View File

@ -1,41 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.cdi.weld;
import org.jboss.weld.context.bound.BoundConversationContext;
public class WeldConversationContext
{
public static void activate(BoundConversationContext boundConversationContext)
{
// TODO Auto-generated method stub
}
public static void deactivate()
{
// TODO Auto-generated method stub
}
public static void invalidate()
{
// TODO Auto-generated method stub
}
}

View File

@ -1,41 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.cdi.weld;
import org.jboss.weld.context.bound.BoundRequestContext;
public class WeldRequestContext
{
public static void activate(BoundRequestContext boundRequestContext)
{
// TODO Auto-generated method stub
}
public static void deactivate()
{
// TODO Auto-generated method stub
}
public static void invalidate()
{
// TODO Auto-generated method stub
}
}

View File

@ -1,77 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.cdi.weld;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
import org.jboss.weld.context.bound.BoundConversationContext;
import org.jboss.weld.context.bound.BoundRequestContext;
import org.jboss.weld.manager.BeanManagerImpl;
/**
* CDI/Weld scopes initialization of WebSocket specific Weld Contexts.
*/
public class WeldScopeInitializer
{
private static final Logger LOG = Log.getLogger(WeldScopeInitializer.class);
@Inject
private ServletContext servletContext;
@Inject
private BoundRequestContext boundRequestContext;
@Inject
private BoundConversationContext boundConversationContext;
@Inject
private BeanManagerImpl beanManager;
private WeldConversationContext conversationContext;
private WeldRequestContext requestContext;
private WeldSessionContext sessionCOntext;
public void activate(WebSocketContainerScope scope)
{
LOG.info("activate(WebSocketContainerScope:{})",scope);
WeldConversationContext.activate(boundConversationContext);
WeldSessionContext.activate(beanManager);
WeldRequestContext.activate(boundRequestContext);
}
public void deactivate(WebSocketContainerScope scope)
{
LOG.info("deactivate(WebSocketContainerScope:{})",scope);
WeldConversationContext.deactivate();
WeldSessionContext.deactivate();
WeldRequestContext.deactivate();
}
public void invalidate(WebSocketContainerScope scope)
{
LOG.info("invalidate(WebSocketContainerScope:{})",scope);
WeldConversationContext.invalidate();
WeldSessionContext.invalidate();
WeldRequestContext.invalidate();
}
}

View File

@ -1,44 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.cdi.weld;
import org.jboss.weld.manager.BeanManagerImpl;
public class WeldSessionContext
{
public static void activate(BeanManagerImpl beanManager)
{
// TODO Auto-generated method stub
}
public static void deactivate()
{
// TODO Auto-generated method stub
}
public static void invalidate()
{
// TODO Auto-generated method stub
}
}

View File

@ -47,9 +47,9 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class WeldScopeInitializerTest
public class WeldInitializationTest
{
private static final Logger LOG = Log.getLogger(WeldScopeInitializerTest.class);
private static final Logger LOG = Log.getLogger(WeldInitializationTest.class);
private static Server server;
private static URI serverHttpURI;
private static URI serverWebsocketURI;

View File

@ -47,11 +47,6 @@ public class CdiInfoSocket
private Session session;
public CdiInfoSocket()
{
Thread.dumpStack();
}
@OnOpen
public void onOpen(Session session)
{
@ -76,8 +71,8 @@ public class CdiInfoSocket
{
case "info":
out.printf("websocketSession is %s%n",asPresent(session));
out.printf("httpSession: %s%n",asPresent(httpSession));
out.printf("servletContext: %s%n",asPresent(servletContext));
out.printf("httpSession is %s%n",asPresent(httpSession));
out.printf("servletContext is %s%n",asPresent(servletContext));
break;
}

View File

@ -88,7 +88,7 @@ public class ServletContextHandler extends ContextHandler
public interface ServletContainerInitializerCaller extends LifeCycle {};
protected final DecoratedObjectFactory _instantiator= new DecoratedObjectFactory();
protected final DecoratedObjectFactory _objFactory = new DecoratedObjectFactory();
protected Class<? extends SecurityHandler> _defaultSecurityHandlerClass=org.eclipse.jetty.security.ConstraintSecurityHandler.class;
protected SessionHandler _sessionHandler;
protected SecurityHandler _securityHandler;
@ -252,7 +252,7 @@ public class ServletContextHandler extends ContextHandler
@Override
protected void doStart() throws Exception
{
setAttribute(DecoratedObjectFactory.ATTR, _instantiator);
getServletContext().setAttribute(DecoratedObjectFactory.ATTR, _objFactory);
super.doStart();
}
@ -264,7 +264,7 @@ public class ServletContextHandler extends ContextHandler
protected void doStop() throws Exception
{
super.doStop();
_instantiator.clear();
_objFactory.clear();
}
/* ------------------------------------------------------------ */
@ -331,7 +331,7 @@ public class ServletContextHandler extends ContextHandler
{
for (ListenerHolder holder:_servletHandler.getListeners())
{
_instantiator.decorate(holder.getListener());
_objFactory.decorate(holder.getListener());
}
}
}
@ -647,17 +647,28 @@ public class ServletContextHandler extends ContextHandler
h.setHandler(handler);
relinkHandlers();
}
/* ------------------------------------------------------------ */
/**
* The DecoratedObjectFactory for use by IoC containers (weld / spring / etc)
*
* @return The DecoratedObjectFactory
*/
public DecoratedObjectFactory getObjectFactory()
{
return _objFactory;
}
/* ------------------------------------------------------------ */
/**
* @return The decorator list used to resource inject new Filters, Servlets and EventListeners
* @deprecated use getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") instead
* @deprecated use the {@link DecoratedObjectFactory} from getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") or {@link #getObjectFactory()} instead
*/
@Deprecated
public List<Decorator> getDecorators()
{
List<Decorator> ret = new ArrayList<ServletContextHandler.Decorator>();
for (org.eclipse.jetty.util.Decorator decorator : _instantiator)
for (org.eclipse.jetty.util.Decorator decorator : _objFactory)
{
ret.add(new LegacyDecorator(decorator));
}
@ -667,31 +678,35 @@ public class ServletContextHandler extends ContextHandler
/* ------------------------------------------------------------ */
/**
* @param decorators The list of {@link Decorator}s
* @deprecated use the {@link DecoratedObjectFactory} from getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") or {@link #getObjectFactory()} instead
*/
@Deprecated
public void setDecorators(List<Decorator> decorators)
{
_instantiator.setDecorators(decorators);
_objFactory.setDecorators(decorators);
}
/* ------------------------------------------------------------ */
/**
* @param decorator The decorator to add
* @deprecated use the {@link DecoratedObjectFactory} from getAttribute("org.eclipse.jetty.util.DecoratedObjectFactory") or {@link #getObjectFactory()} instead
*/
@Deprecated
public void addDecorator(Decorator decorator)
{
_instantiator.addDecorator(decorator);
_objFactory.addDecorator(decorator);
}
/* ------------------------------------------------------------ */
void destroyServlet(Servlet servlet)
{
_instantiator.destroy(servlet);
_objFactory.destroy(servlet);
}
/* ------------------------------------------------------------ */
void destroyFilter(Filter filter)
{
_instantiator.destroy(filter);
_objFactory.destroy(filter);
}
/* ------------------------------------------------------------ */
@ -1244,7 +1259,7 @@ public class ServletContextHandler extends ContextHandler
try
{
T f = createInstance(c);
f = _instantiator.decorate(f);
f = _objFactory.decorate(f);
return f;
}
catch (Exception e)
@ -1260,7 +1275,7 @@ public class ServletContextHandler extends ContextHandler
try
{
T s = createInstance(c);
s = _instantiator.decorate(s);
s = _objFactory.decorate(s);
return s;
}
catch (Exception e)
@ -1403,7 +1418,7 @@ public class ServletContextHandler extends ContextHandler
try
{
T l = createInstance(clazz);
l = _instantiator.decorate(l);
l = _objFactory.decorate(l);
return l;
}
catch (Exception e)

View File

@ -18,15 +18,12 @@
package org.eclipse.jetty.servlet;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@ -52,6 +49,8 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Assert;
@ -361,6 +360,59 @@ public class ServletContextHandlerTest
Assert.assertThat(response, Matchers.containsString("404 Fell Through"));
}
/**
* Test behavior of legacy {@link ServletContextHandler.Decorator}, with
* new DecoratedObjectFactory class
*/
@SuppressWarnings("deprecation")
@Test
public void testLegacyDecorator() throws Exception
{
ServletContextHandler context = new ServletContextHandler();
context.addDecorator(new DummyLegacyDecorator());
_server.setHandler(context);
context.addServlet(DecoratedObjectFactoryServlet.class, "/objfactory/*");
_server.start();
String response= _connector.getResponses("GET /objfactory/ HTTP/1.0\r\n\r\n");
assertThat("Response status code", response, containsString("200 OK"));
String expected = String.format("Attribute[%s] = %s", DecoratedObjectFactory.ATTR, DecoratedObjectFactory.class.getName());
assertThat("Has context attribute", response, containsString(expected));
assertThat("Decorators size", response, containsString("Decorators.size = [1]"));
expected = String.format("decorator[] = %s", DummyLegacyDecorator.class.getName());
assertThat("Specific Legacy Decorator", response, containsString(expected));
}
/**
* Test behavior of new {@link org.eclipse.jetty.util.Decorator}, with
* new DecoratedObjectFactory class
*/
@Test
public void testUtilDecorator() throws Exception
{
ServletContextHandler context = new ServletContextHandler();
context.getObjectFactory().addDecorator(new DummyUtilDecorator());
_server.setHandler(context);
context.addServlet(DecoratedObjectFactoryServlet.class, "/objfactory/*");
_server.start();
String response= _connector.getResponses("GET /objfactory/ HTTP/1.0\r\n\r\n");
assertThat("Response status code", response, containsString("200 OK"));
String expected = String.format("Attribute[%s] = %s", DecoratedObjectFactory.ATTR, DecoratedObjectFactory.class.getName());
assertThat("Has context attribute", response, containsString(expected));
assertThat("Decorators size", response, containsString("Decorators.size = [1]"));
expected = String.format("decorator[] = %s", DummyUtilDecorator.class.getName());
assertThat("Specific Legacy Decorator", response, containsString(expected));
}
private int assertResponseContains(String expected, String response)
{
@ -391,6 +443,66 @@ public class ServletContextHandlerTest
writer.write("Hello World");
}
}
public static class DummyUtilDecorator implements org.eclipse.jetty.util.Decorator
{
@Override
public <T> T decorate(T o)
{
return o;
}
@Override
public void destroy(Object o)
{
}
}
public static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator
{
@Override
public <T> T decorate(T o)
{
return o;
}
@Override
public void destroy(Object o)
{
}
}
public static class DecoratedObjectFactoryServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setContentType("text/plain");
resp.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = resp.getWriter();
Object obj = req.getServletContext().getAttribute(DecoratedObjectFactory.ATTR);
out.printf("Attribute[%s] = %s%n",DecoratedObjectFactory.ATTR,obj.getClass().getName());
if (obj instanceof DecoratedObjectFactory)
{
out.printf("Object is a DecoratedObjectFactory%n");
DecoratedObjectFactory objFactory = (DecoratedObjectFactory)obj;
List<Decorator> decorators = objFactory.getDecorators();
out.printf("Decorators.size = [%d]%n",decorators.size());
for (Decorator decorator : decorators)
{
out.printf(" decorator[] = %s%n",decorator.getClass().getName());
}
}
else
{
out.printf("Object is NOT a DecoratedObjectFactory%n");
}
}
}
public static class TestServlet extends HttpServlet
{

View File

@ -62,7 +62,7 @@ public class DecoratedObjectFactory implements Iterable<Decorator>
{
if (LOG.isDebugEnabled())
{
LOG.debug("Creating Instance: " + clazz,new Throwable("Creation Stack"));
LOG.debug("Creating Instance: " + clazz);
}
T o = clazz.newInstance();
return decorate(o);
@ -106,4 +106,14 @@ public class DecoratedObjectFactory implements Iterable<Decorator>
this.decorators.addAll(decorators);
}
}
@Override
public String toString()
{
StringBuilder str = new StringBuilder();
str.append(this.getClass().getName()).append("[decorators=");
str.append(Integer.toString(decorators.size()));
str.append("]");
return str.toString();
}
}

View File

@ -77,6 +77,8 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
{
private static final Logger LOG = Log.getLogger(ClientContainer.class);
/** The delegated Container Scope */
private final WebSocketContainerScope scopeDelegate;
/** Tracking all primitive decoders for the container */
private final DecoderFactory decoderFactory;
/** Tracking all primitive encoders for the container */
@ -89,8 +91,6 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
/** The jetty websocket client in use for this container */
private WebSocketClient client;
protected DecoratedObjectFactory objectFactory;
public ClientContainer()
{
// This constructor is used with Standalone JSR Client usage.
@ -102,6 +102,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
{
boolean trustAll = Boolean.getBoolean("org.eclipse.jetty.websocket.jsr356.ssl-trust-all");
this.scopeDelegate = scope;
client = new WebSocketClient(scope, new SslContextFactory(trustAll));
client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy()));
SessionFactory sessionFactory = new JsrSessionFactory(this,this,client);
@ -112,10 +113,6 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
this.decoderFactory = new DecoderFactory(this,PrimitiveDecoderMetadataSet.INSTANCE);
this.encoderFactory = new EncoderFactory(this,PrimitiveEncoderMetadataSet.INSTANCE);
EmptyClientEndpointConfig empty = new EmptyClientEndpointConfig();
this.decoderFactory.init(empty);
this.encoderFactory.init(empty);
ShutdownThread.register(this);
}
@ -196,7 +193,18 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
EndpointInstance instance = newClientEndpointInstance(endpoint,null);
return connect(instance,path);
}
@Override
protected void doStart() throws Exception
{
super.doStart();
// Initialize the default decoder / encoder factories
EmptyClientEndpointConfig empty = new EmptyClientEndpointConfig();
this.decoderFactory.init(empty);
this.encoderFactory.init(empty);
}
@Override
protected void doStop() throws Exception
{
@ -208,7 +216,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
@Override
public ByteBufferPool getBufferPool()
{
return client.getBufferPool();
return scopeDelegate.getBufferPool();
}
public WebSocketClient getClient()
@ -297,7 +305,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
@Override
public Executor getExecutor()
{
return client.getExecutor();
return scopeDelegate.getExecutor();
}
@Override
@ -317,7 +325,7 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
@Override
public DecoratedObjectFactory getObjectFactory()
{
return client.getObjectFactory();
return scopeDelegate.getObjectFactory();
}
/**
@ -331,13 +339,13 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
@Override
public WebSocketPolicy getPolicy()
{
return client.getPolicy();
return scopeDelegate.getPolicy();
}
@Override
public SslContextFactory getSslContextFactory()
{
return client.getSslContextFactory();
return scopeDelegate.getSslContextFactory();
}
private EndpointInstance newClientEndpointInstance(Class<?> endpointClass, ClientEndpointConfig config)

View File

@ -25,7 +25,6 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.Decoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
@ -76,7 +75,7 @@ public class DecoderFactory implements Configurable
private static final Logger LOG = Log.getLogger(DecoderFactory.class);
private final DecoderMetadataSet metadatas;
private final DecoratedObjectFactory objectFactory;
private final WebSocketContainerScope containerScope;
private DecoderFactory parentFactory;
private Map<Class<?>, Wrapper> activeWrappers;
@ -93,7 +92,7 @@ public class DecoderFactory implements Configurable
protected DecoderFactory(WebSocketContainerScope containerScope, DecoderMetadataSet metadatas, DecoderFactory parentFactory)
{
Objects.requireNonNull(containerScope,"Container Scope cannot be null");
this.objectFactory = containerScope.getObjectFactory();
this.containerScope = containerScope;
this.metadatas = metadatas;
this.activeWrappers = new ConcurrentHashMap<>();
this.parentFactory = parentFactory;
@ -186,7 +185,7 @@ public class DecoderFactory implements Configurable
Class<? extends Decoder> decoderClass = metadata.getCoderClass();
try
{
Decoder decoder = objectFactory.createInstance(decoderClass);
Decoder decoder = containerScope.getObjectFactory().createInstance(decoderClass);
return new Wrapper(decoder,metadata);
}
catch (InstantiationException | IllegalAccessException e)

View File

@ -25,7 +25,6 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
@ -69,7 +68,7 @@ public class EncoderFactory implements Configurable
private static final Logger LOG = Log.getLogger(EncoderFactory.class);
private final EncoderMetadataSet metadatas;
private final DecoratedObjectFactory objectFactory;
private final WebSocketContainerScope containerScope;
private EncoderFactory parentFactory;
private Map<Class<?>, Wrapper> activeWrappers;
@ -86,7 +85,7 @@ public class EncoderFactory implements Configurable
protected EncoderFactory(WebSocketContainerScope containerScope, EncoderMetadataSet metadatas, EncoderFactory parentFactory)
{
Objects.requireNonNull(containerScope,"Container Scope cannot be null");
this.objectFactory = containerScope.getObjectFactory();
this.containerScope = containerScope;
this.metadatas = metadatas;
this.activeWrappers = new ConcurrentHashMap<>();
this.parentFactory = parentFactory;
@ -179,7 +178,7 @@ public class EncoderFactory implements Configurable
Class<? extends Encoder> encoderClass = metadata.getCoderClass();
try
{
Encoder encoder = objectFactory.createInstance(encoderClass);
Encoder encoder = containerScope.getObjectFactory().createInstance(encoderClass);
return new Wrapper(encoder,metadata);
}
catch (InstantiationException | IllegalAccessException e)

View File

@ -22,16 +22,24 @@ import javax.websocket.ContainerProvider;
import javax.websocket.WebSocketContainer;
/**
* Client {@link ContainerProvider} implementation
* Client {@link ContainerProvider} implementation.
* <p>
* Created by a {@link java.util.ServiceLoader} call in the
* {@link javax.websocket.ContainerProvider#getWebSocketContainer()} call.
*/
public class JettyClientContainerProvider extends ContainerProvider
{
/**
* Used by {@link ContainerProvider#getWebSocketContainer()} to get a new instance
* of the Client {@link WebSocketContainer}.
*/
@Override
protected WebSocketContainer getContainer()
{
ClientContainer container = new ClientContainer();
try
{
// We need to start this container properly.
container.start();
return container;
}

View File

@ -1,5 +1,6 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.websocket.LEVEL=INFO
# org.eclipse.jetty.websocket.LEVEL=ALL
# org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG

View File

@ -122,7 +122,7 @@ public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
}
else
{
cfgr = new BasicServerEndpointConfigurator(containerScope);
cfgr = new ContainerDefaultConfigurator();
}
}
else
@ -144,7 +144,6 @@ public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
// Make sure all Configurators obtained are decorated
this.configurator = containerScope.getObjectFactory().decorate(cfgr);
}
@Override

View File

@ -51,7 +51,7 @@ public class BasicServerEndpointConfig implements ServerEndpointConfig
this.subprotocols = new ArrayList<>();
this.extensions = new ArrayList<>();
this.userProperties = new HashMap<>();
this.configurator = new BasicServerEndpointConfigurator(containerScope);
this.configurator = new ContainerDefaultConfigurator();
}
public BasicServerEndpointConfig(WebSocketContainerScope containerScope, ServerEndpointConfig copy)
@ -73,7 +73,7 @@ public class BasicServerEndpointConfig implements ServerEndpointConfig
}
else
{
cfgr = new BasicServerEndpointConfigurator(containerScope);
cfgr = new ContainerDefaultConfigurator();
}
// Make sure all Configurators obtained are decorated

View File

@ -1,57 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
/**
* The Basic Configurator
*/
public class BasicServerEndpointConfigurator extends ContainerDefaultConfigurator
{
private static final Logger LOG = Log.getLogger(BasicServerEndpointConfigurator.class);
private final DecoratedObjectFactory objectFactory;
public BasicServerEndpointConfigurator(WebSocketContainerScope containerScope)
{
super();
this.objectFactory = containerScope.getObjectFactory();
}
@Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
{
if (LOG.isDebugEnabled())
{
LOG.debug(".getEndpointInstance({})",endpointClass);
}
try
{
return objectFactory.createInstance(endpointClass);
}
catch (IllegalAccessException e)
{
throw new InstantiationException(String.format("%s: %s",e.getClass().getName(),e.getMessage()));
}
}
}

View File

@ -35,7 +35,7 @@ import org.eclipse.jetty.websocket.api.util.QuoteUtil;
*
* @see ServiceLoader behavior of {@link ServerEndpointConfig.Configurator}
*/
public class ContainerDefaultConfigurator extends Configurator
public final class ContainerDefaultConfigurator extends Configurator
{
private static final Logger LOG = Log.getLogger(ContainerDefaultConfigurator.class);
private static final String NO_SUBPROTOCOL = "";

View File

@ -25,6 +25,7 @@ import java.util.List;
import javax.websocket.Extension;
import javax.websocket.Extension.Parameter;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
@ -137,7 +138,13 @@ public class JsrCreator implements WebSocketCreator
try
{
Class<?> endpointClass = config.getEndpointClass();
Object endpoint = config.getConfigurator().getEndpointInstance(endpointClass);
Configurator configr = config.getConfigurator();
Object endpoint = configr.getEndpointInstance(endpointClass);
if (configr instanceof ContainerDefaultConfigurator)
{
// default impl always decorates (custom ones do not)
endpoint = containerScope.getObjectFactory().decorate(endpoint);
}
PathSpec pathSpec = hsreq.getRequestPathSpec();
if (pathSpec instanceof WebSocketPathSpec)
{

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.websocket.jsr356.server;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import javax.websocket.DeploymentException;
@ -43,16 +45,19 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
private final MappedWebSocketCreator mappedCreator;
private final WebSocketServerFactory webSocketServerFactory;
private List<Class<?>> deferredEndpointClasses;
private List<ServerEndpointConfig> deferredEndpointConfigs;
public ServerContainer(MappedWebSocketCreator creator, WebSocketServerFactory factory, Executor executor)
{
super();
super(factory);
this.mappedCreator = creator;
this.webSocketServerFactory = factory;
EventDriverFactory eventDriverFactory = this.webSocketServerFactory.getEventDriverFactory();
eventDriverFactory.addImplementation(new JsrServerEndpointImpl());
eventDriverFactory.addImplementation(new JsrServerExtendsEndpointImpl());
this.webSocketServerFactory.addSessionFactory(new JsrSessionFactory(this,this));
addBean(webSocketServerFactory);
}
public EndpointInstance newClientEndpointInstance(Object endpoint, ServerEndpointConfig config, String path)
@ -76,11 +81,22 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
@Override
public void addEndpoint(Class<?> endpointClass) throws DeploymentException
{
ServerEndpointMetadata metadata = getServerEndpointMetadata(endpointClass,null);
addEndpoint(metadata);
if (isStarted() || isStarting())
{
ServerEndpointMetadata metadata = getServerEndpointMetadata(endpointClass,null);
addEndpoint(metadata);
}
else
{
if (deferredEndpointClasses == null)
{
deferredEndpointClasses = new ArrayList<Class<?>>();
}
deferredEndpointClasses.add(endpointClass);
}
}
public void addEndpoint(ServerEndpointMetadata metadata) throws DeploymentException
private void addEndpoint(ServerEndpointMetadata metadata) throws DeploymentException
{
JsrCreator creator = new JsrCreator(this,metadata,webSocketServerFactory.getExtensionFactory());
mappedCreator.addMapping(new WebSocketPathSpec(metadata.getPath()),creator);
@ -89,12 +105,50 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
@Override
public void addEndpoint(ServerEndpointConfig config) throws DeploymentException
{
if (LOG.isDebugEnabled())
if (isStarted() || isStarting())
{
LOG.debug("addEndpoint({}) path={} endpoint={}",config,config.getPath(),config.getEndpointClass());
if (LOG.isDebugEnabled())
{
LOG.debug("addEndpoint({}) path={} endpoint={}",config,config.getPath(),config.getEndpointClass());
}
ServerEndpointMetadata metadata = getServerEndpointMetadata(config.getEndpointClass(),config);
addEndpoint(metadata);
}
ServerEndpointMetadata metadata = getServerEndpointMetadata(config.getEndpointClass(),config);
addEndpoint(metadata);
else
{
if (deferredEndpointConfigs == null)
{
deferredEndpointConfigs = new ArrayList<ServerEndpointConfig>();
}
deferredEndpointConfigs.add(config);
}
}
@Override
protected void doStart() throws Exception
{
// Proceed with Normal Startup
super.doStart();
// Process Deferred Endpoints
if (deferredEndpointClasses != null)
{
for (Class<?> endpointClass : deferredEndpointClasses)
{
addEndpoint(endpointClass);
}
}
if (deferredEndpointConfigs != null)
{
for (ServerEndpointConfig config : deferredEndpointConfigs)
{
addEndpoint(config);
}
}
deferredEndpointClasses.clear();
deferredEndpointConfigs.clear();
}
public ServerEndpointMetadata getServerEndpointMetadata(final Class<?> endpoint, final ServerEndpointConfig config) throws DeploymentException

View File

@ -58,7 +58,6 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
// Create the Jetty ServerContainer implementation
filter.getFactory().init(context);
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),context.getServer().getThreadPool());
context.addBean(jettyContainer);
@ -79,7 +78,6 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
// Create the Jetty ServerContainer implementation
filter.getFactory().init(context);
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory(),jettyContext.getServer().getThreadPool());
jettyContext.addBean(jettyContainer);

View File

@ -381,7 +381,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
public void init(ServletContextHandler context) throws ServletException
{
this.objectFactory = (DecoratedObjectFactory)context.getAttribute(DecoratedObjectFactory.ATTR);
this.objectFactory = (DecoratedObjectFactory)context.getServletContext().getAttribute(DecoratedObjectFactory.ATTR);
if (this.objectFactory == null)
{
this.objectFactory = new DecoratedObjectFactory();

View File

@ -257,7 +257,8 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
try
{
factory.init(config.getServletContext());
ServletContext ctx = config.getServletContext();
factory.init(ctx);
WebSocketPolicy policy = factory.getPolicy();
String max = config.getInitParameter("maxIdleTime");
@ -291,7 +292,7 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
key = WebSocketUpgradeFilter.class.getName();
}
setToAttribute(config.getServletContext(), key);
setToAttribute(ctx, key);
factory.start();
}

View File

@ -0,0 +1,179 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.server;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.toolchain.test.EventQueue;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class DecoratorsLegacyTest
{
private static class DecoratorsSocket extends WebSocketAdapter
{
private final DecoratedObjectFactory objFactory;
public DecoratorsSocket(DecoratedObjectFactory objFactory)
{
this.objFactory = objFactory;
}
@Override
public void onWebSocketText(String message)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
if (objFactory != null)
{
out.printf("Object is a DecoratedObjectFactory%n");
List<Decorator> decorators = objFactory.getDecorators();
out.printf("Decorators.size = [%d]%n",decorators.size());
for (Decorator decorator : decorators)
{
out.printf(" decorator[] = %s%n",decorator.getClass().getName());
}
}
else
{
out.printf("DecoratedObjectFactory is NULL%n");
}
getRemote().sendStringByFuture(str.toString());
}
}
private static class DecoratorsCreator implements WebSocketCreator
{
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
ServletContext servletContext = req.getHttpServletRequest().getServletContext();
DecoratedObjectFactory objFactory = (DecoratedObjectFactory)servletContext.getAttribute(DecoratedObjectFactory.ATTR);
return new DecoratorsSocket(objFactory);
}
}
public static class DecoratorsRequestServlet extends WebSocketServlet
{
private static final long serialVersionUID = 1L;
private final WebSocketCreator creator;
public DecoratorsRequestServlet(WebSocketCreator creator)
{
this.creator = creator;
}
@Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(this.creator);
}
}
private static class DummyLegacyDecorator implements org.eclipse.jetty.servlet.ServletContextHandler.Decorator
{
@Override
public <T> T decorate(T o)
{
return o;
}
@Override
public void destroy(Object o)
{
}
}
private static SimpleServletServer server;
private static DecoratorsCreator decoratorsCreator;
@BeforeClass
public static void startServer() throws Exception
{
decoratorsCreator = new DecoratorsCreator();
server = new SimpleServletServer(new DecoratorsRequestServlet(decoratorsCreator))
{
@SuppressWarnings("deprecation")
@Override
protected void configureServletContextHandler(ServletContextHandler context)
{
// Add decorator in the legacy way
context.addDecorator(new DummyLegacyDecorator());
}
};
server.start();
}
@AfterClass
public static void stopServer()
{
server.stop();
}
@Test
public void testAccessRequestCookies() throws Exception
{
BlockheadClient client = new BlockheadClient(server.getServerUri());
client.setTimeout(1,TimeUnit.SECONDS);
try
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("info"));
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
WebSocketFrame resp = frames.poll();
String textMsg = resp.getPayloadAsUTF8();
assertThat("DecoratedObjectFactory", textMsg, containsString("Object is a DecoratedObjectFactory"));
assertThat("decorators.size", textMsg, containsString("Decorators.size = [1]"));
assertThat("decorator type", textMsg, containsString("decorator[] = " + DummyLegacyDecorator.class.getName()));
}
finally
{
client.close();
}
}
}

View File

@ -0,0 +1,178 @@
//
// ========================================================================
// Copyright (c) 1995-2015 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.server;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletContext;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.toolchain.test.EventQueue;
import org.eclipse.jetty.util.DecoratedObjectFactory;
import org.eclipse.jetty.util.Decorator;
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.frames.TextFrame;
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class DecoratorsTest
{
private static class DecoratorsSocket extends WebSocketAdapter
{
private final DecoratedObjectFactory objFactory;
public DecoratorsSocket(DecoratedObjectFactory objFactory)
{
this.objFactory = objFactory;
}
@Override
public void onWebSocketText(String message)
{
StringWriter str = new StringWriter();
PrintWriter out = new PrintWriter(str);
if (objFactory != null)
{
out.printf("Object is a DecoratedObjectFactory%n");
List<Decorator> decorators = objFactory.getDecorators();
out.printf("Decorators.size = [%d]%n",decorators.size());
for (Decorator decorator : decorators)
{
out.printf(" decorator[] = %s%n",decorator.getClass().getName());
}
}
else
{
out.printf("DecoratedObjectFactory is NULL%n");
}
getRemote().sendStringByFuture(str.toString());
}
}
private static class DecoratorsCreator implements WebSocketCreator
{
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
ServletContext servletContext = req.getHttpServletRequest().getServletContext();
DecoratedObjectFactory objFactory = (DecoratedObjectFactory)servletContext.getAttribute(DecoratedObjectFactory.ATTR);
return new DecoratorsSocket(objFactory);
}
}
public static class DecoratorsRequestServlet extends WebSocketServlet
{
private static final long serialVersionUID = 1L;
private final WebSocketCreator creator;
public DecoratorsRequestServlet(WebSocketCreator creator)
{
this.creator = creator;
}
@Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(this.creator);
}
}
private static class DummyUtilDecorator implements org.eclipse.jetty.util.Decorator
{
@Override
public <T> T decorate(T o)
{
return o;
}
@Override
public void destroy(Object o)
{
}
}
private static SimpleServletServer server;
private static DecoratorsCreator decoratorsCreator;
@BeforeClass
public static void startServer() throws Exception
{
decoratorsCreator = new DecoratorsCreator();
server = new SimpleServletServer(new DecoratorsRequestServlet(decoratorsCreator))
{
@Override
protected void configureServletContextHandler(ServletContextHandler context)
{
// Add decorator in the new util way
context.getObjectFactory().addDecorator(new DummyUtilDecorator());
}
};
server.start();
}
@AfterClass
public static void stopServer()
{
server.stop();
}
@Test
public void testAccessRequestCookies() throws Exception
{
BlockheadClient client = new BlockheadClient(server.getServerUri());
client.setTimeout(1,TimeUnit.SECONDS);
try
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("info"));
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
WebSocketFrame resp = frames.poll();
String textMsg = resp.getPayloadAsUTF8();
assertThat("DecoratedObjectFactory", textMsg, containsString("Object is a DecoratedObjectFactory"));
assertThat("decorators.size", textMsg, containsString("Decorators.size = [1]"));
assertThat("decorator type", textMsg, containsString("decorator[] = " + DummyUtilDecorator.class.getName()));
}
finally
{
client.close();
}
}
}

View File

@ -114,6 +114,7 @@ public class SimpleServletServer
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
configureServletContextHandler(context);
server.setHandler(context);
// Serve capture servlet
@ -138,6 +139,10 @@ public class SimpleServletServer
}
}
protected void configureServletContextHandler(ServletContextHandler context)
{
}
public void stop()
{
try

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.servlet;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
@ -128,10 +129,12 @@ public abstract class WebSocketServlet extends HttpServlet
factory = WebSocketServletFactory.Loader.create(policy);
configure(factory);
factory.init(getServletContext());
getServletContext().setAttribute(WebSocketServletFactory.class.getName(),factory);
ServletContext ctx = getServletContext();
factory.init(ctx);
ctx.setAttribute(WebSocketServletFactory.class.getName(),factory);
}
catch (Exception x)
{