417152 - WebSocket / Do all setup in websocket specific ServletContainerInitializer
+ Removed WebSocketConfiguration class entirely + annotation handlers + Renamed ServerAppliationConfigListener to WebSocketServerContainerInitializer + Embedded jetty code that used to use: WebSocketContainer.configureContext(context) now uses WebSocketServerContainerInitializer.configureContext(context)
This commit is contained in:
parent
cc9c19fd9d
commit
cd236bc016
|
@ -25,7 +25,7 @@ import javax.websocket.server.ServerEndpoint;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
|
||||
/**
|
||||
* Example of setting up a javax.websocket server with Jetty embedded
|
||||
|
@ -54,7 +54,7 @@ public class WebSocketJsrServer
|
|||
server.setHandler(context);
|
||||
|
||||
// Enable javax.websocket configuration for the context
|
||||
ServerContainer wsContainer = WebSocketConfiguration.configureContext(context);
|
||||
ServerContainer wsContainer = WebSocketServerContainerInitializer.configureContext(context);
|
||||
|
||||
// Add your websockets to the container
|
||||
wsContainer.addEndpoint(EchoJsrSocket.class);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-annotations</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
|
|
|
@ -1,123 +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.server;
|
||||
|
||||
import org.eclipse.jetty.annotations.AnnotationConfiguration;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
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.jsr356.server.deploy.DiscoveredEndpoints;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.ServerEndpointAnnotationHandler;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
|
||||
/**
|
||||
* WebSocket Server Configuration component.
|
||||
* <p>
|
||||
* This configuration will configure a context for JSR356 Websockets.
|
||||
* <p>
|
||||
* It is possible to disable specific contexts with an attribute <code>"org.eclipse.jetty.websocket.jsr356"</code> (set to <code>"false"</code>)
|
||||
* <p>
|
||||
* This attribute may be set on an individual context, or on the server to affect all deployed contexts.
|
||||
*/
|
||||
public class WebSocketConfiguration extends AbstractConfiguration
|
||||
{
|
||||
public static final String ENABLE = "org.eclipse.jetty.websocket.jsr356";
|
||||
private static final Logger LOG = Log.getLogger(WebSocketConfiguration.class);
|
||||
|
||||
/**
|
||||
* Create a ServerContainer properly, useful for embedded application use.
|
||||
* <p>
|
||||
* Notably, the cometd3 project uses this.
|
||||
*
|
||||
* @param context
|
||||
* the context to enable javax.websocket support filters on
|
||||
* @return the ServerContainer that was created
|
||||
*/
|
||||
public static ServerContainer configureContext(ServletContextHandler context)
|
||||
{
|
||||
LOG.debug("Configure javax.websocket for WebApp {}",context);
|
||||
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory());
|
||||
context.addBean(jettyContainer);
|
||||
|
||||
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
|
||||
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
|
||||
|
||||
// Store reference to DiscoveredEndpoints
|
||||
context.setAttribute(DiscoveredEndpoints.class.getName(),new DiscoveredEndpoints());
|
||||
|
||||
return jettyContainer;
|
||||
}
|
||||
|
||||
public static boolean isJSR356Context(ContextHandler context)
|
||||
{
|
||||
Object enable = context.getAttribute(ENABLE);
|
||||
if (enable instanceof Boolean)
|
||||
{
|
||||
return ((Boolean)enable).booleanValue();
|
||||
}
|
||||
|
||||
enable = context.getServer().getAttribute(ENABLE);
|
||||
if (enable instanceof Boolean)
|
||||
{
|
||||
return ((Boolean)enable).booleanValue();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebAppContext context) throws Exception
|
||||
{
|
||||
if (isJSR356Context(context))
|
||||
{
|
||||
WebSocketConfiguration.configureContext(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("JSR-356 support disabled for WebApp {}",context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preConfigure(WebAppContext context) throws Exception
|
||||
{
|
||||
if (isJSR356Context(context))
|
||||
{
|
||||
boolean scanningAdded = false;
|
||||
// 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));
|
||||
scanningAdded = true;
|
||||
}
|
||||
}
|
||||
LOG.debug("@ServerEndpoint scanning added: {}",scanningAdded);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,158 +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.server.deploy;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.websocket.Endpoint;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* Tracking for Discovered Endpoints.
|
||||
* <p>
|
||||
* This is a collection of endpoints, grouped by type (by Annotation or by extending Endpoint). Along with some better error messages for conflicting endpoints.
|
||||
*/
|
||||
public class DiscoveredEndpoints
|
||||
{
|
||||
private static class LocatedClass
|
||||
{
|
||||
private Class<?> clazz;
|
||||
|
||||
private URI location;
|
||||
public LocatedClass(Class<?> clazz)
|
||||
{
|
||||
this.clazz = clazz;
|
||||
this.location = getArchiveURI(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("LocatedClass[");
|
||||
builder.append(clazz.getName());
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(DiscoveredEndpoints.class);
|
||||
|
||||
public static URI getArchiveURI(Class<?> clazz)
|
||||
{
|
||||
String resourceName = clazz.getName().replace('.','/') + ".class";
|
||||
URL classUrl = clazz.getClassLoader().getResource(resourceName);
|
||||
if (classUrl == null)
|
||||
{
|
||||
// is this even possible at this point?
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
URI uri = classUrl.toURI();
|
||||
String scheme = uri.getScheme();
|
||||
if (scheme.equalsIgnoreCase("jar"))
|
||||
{
|
||||
String ssp = uri.getSchemeSpecificPart();
|
||||
int idx = ssp.indexOf("!/");
|
||||
if (idx >= 0)
|
||||
{
|
||||
ssp = ssp.substring(0,idx);
|
||||
}
|
||||
return URI.create(ssp);
|
||||
}
|
||||
}
|
||||
catch (URISyntaxException e)
|
||||
{
|
||||
LOG.warn("Class reference not a valid URI? " + classUrl,e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private Set<LocatedClass> extendedEndpoints;
|
||||
|
||||
private Set<LocatedClass> annotatedEndpoints;
|
||||
|
||||
public DiscoveredEndpoints()
|
||||
{
|
||||
extendedEndpoints = new HashSet<>();
|
||||
annotatedEndpoints = new HashSet<>();
|
||||
}
|
||||
|
||||
public void addAnnotatedEndpoint(Class<?> endpoint)
|
||||
{
|
||||
this.annotatedEndpoints.add(new LocatedClass(endpoint));
|
||||
}
|
||||
|
||||
public void addExtendedEndpoint(Class<? extends Endpoint> endpoint)
|
||||
{
|
||||
this.extendedEndpoints.add(new LocatedClass(endpoint));
|
||||
}
|
||||
|
||||
public Set<Class<?>> getAnnotatedEndpoints()
|
||||
{
|
||||
Set<Class<?>> endpoints = new HashSet<>();
|
||||
for (LocatedClass lc : annotatedEndpoints)
|
||||
{
|
||||
endpoints.add(lc.clazz);
|
||||
}
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
public void getArchiveSpecificAnnnotatedEndpoints(URI archiveURI, Set<Class<?>> archiveSpecificEndpoints)
|
||||
{
|
||||
for (LocatedClass lc : annotatedEndpoints)
|
||||
{
|
||||
if ((archiveURI == null) || lc.location.getPath().equals(archiveURI.getPath()))
|
||||
{
|
||||
archiveSpecificEndpoints.add(lc.clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void getArchiveSpecificExtendedEndpoints(URI archiveURI, Set<Class<? extends Endpoint>> archiveSpecificEndpoints)
|
||||
{
|
||||
for (LocatedClass lc : extendedEndpoints)
|
||||
{
|
||||
if ((archiveURI == null) || (lc.location.getPath().equals(archiveURI.getPath()) && Endpoint.class.isAssignableFrom(lc.clazz)))
|
||||
{
|
||||
archiveSpecificEndpoints.add((Class<? extends Endpoint>)lc.clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("DiscoveredEndpoints [extendedEndpoints=");
|
||||
builder.append(extendedEndpoints);
|
||||
builder.append(", annotatedEndpoints=");
|
||||
builder.append(annotatedEndpoints);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
|
@ -1,162 +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.server.deploy;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContainerInitializer;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.HandlesTypes;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.server.ServerApplicationConfig;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
|
||||
@HandlesTypes(
|
||||
{ ServerApplicationConfig.class, Endpoint.class })
|
||||
public class ServerApplicationConfigListener implements ServletContainerInitializer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ServerApplicationConfigListener.class);
|
||||
|
||||
@Override
|
||||
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException
|
||||
{
|
||||
if (!WebSocketConfiguration.isJSR356Context(((ContextHandler.Context)ctx).getContextHandler()))
|
||||
return;
|
||||
|
||||
WebSocketUpgradeFilter filter = (WebSocketUpgradeFilter)ctx.getAttribute(WebSocketUpgradeFilter.class.getName());
|
||||
if (filter == null)
|
||||
{
|
||||
LOG.warn("Required attribute not available: " + WebSocketUpgradeFilter.class.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
DiscoveredEndpoints discovered = (DiscoveredEndpoints)ctx.getAttribute(DiscoveredEndpoints.class.getName());
|
||||
if (discovered == null)
|
||||
{
|
||||
LOG.warn("Required attribute not available: " + DiscoveredEndpoints.class.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug("Found {} classes",c.size());
|
||||
LOG.debug("Discovered: {}",discovered);
|
||||
|
||||
// First add all of the Endpoints
|
||||
addEndpoints(c,discovered);
|
||||
|
||||
// Now process the ServerApplicationConfig entries
|
||||
ServerContainer container = (ServerContainer)ctx.getAttribute(javax.websocket.server.ServerContainer.class.getName());
|
||||
Set<Class<? extends Endpoint>> archiveSpecificExtendEndpoints = new HashSet<>();
|
||||
Set<Class<?>> archiveSpecificAnnotatedEndpoints = new HashSet<>();
|
||||
List<Class<? extends ServerApplicationConfig>> serverAppConfigs = filterServerApplicationConfigs(c);
|
||||
|
||||
if(serverAppConfigs.size() >= 1) {
|
||||
for (Class<? extends ServerApplicationConfig> clazz : filterServerApplicationConfigs(c))
|
||||
{
|
||||
LOG.debug("Found ServerApplicationConfig: {}",clazz);
|
||||
try
|
||||
{
|
||||
ServerApplicationConfig config = (ServerApplicationConfig)clazz.newInstance();
|
||||
URI archiveURI = DiscoveredEndpoints.getArchiveURI(clazz);
|
||||
archiveSpecificExtendEndpoints.clear();
|
||||
archiveSpecificAnnotatedEndpoints.clear();
|
||||
discovered.getArchiveSpecificExtendedEndpoints(archiveURI,archiveSpecificExtendEndpoints);
|
||||
discovered.getArchiveSpecificAnnnotatedEndpoints(archiveURI,archiveSpecificAnnotatedEndpoints);
|
||||
|
||||
Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(archiveSpecificExtendEndpoints);
|
||||
if (seconfigs != null)
|
||||
{
|
||||
for (ServerEndpointConfig sec : seconfigs)
|
||||
{
|
||||
container.addEndpoint(sec);
|
||||
}
|
||||
}
|
||||
Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(archiveSpecificAnnotatedEndpoints);
|
||||
if (annotatedClasses != null)
|
||||
{
|
||||
for (Class<?> annotatedClass : annotatedClasses)
|
||||
{
|
||||
container.addEndpoint(annotatedClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Default behavior (no ServerApplicationConfigs found)
|
||||
// Note: it is impossible to determine path of "extends Endpoint" discovered classes
|
||||
for(Class<?> annotatedClass: discovered.getAnnotatedEndpoints())
|
||||
{
|
||||
try
|
||||
{
|
||||
container.addEndpoint(annotatedClass);
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Class<? extends ServerApplicationConfig>> filterServerApplicationConfigs(Set<Class<?>> c)
|
||||
{
|
||||
List<Class<? extends ServerApplicationConfig>> configs = new ArrayList<>();
|
||||
for (Class<?> clazz : c)
|
||||
{
|
||||
if (ServerApplicationConfig.class.isAssignableFrom(clazz))
|
||||
{
|
||||
configs.add((Class<? extends ServerApplicationConfig>)clazz);
|
||||
}
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addEndpoints(Set<Class<?>> c, DiscoveredEndpoints discovered)
|
||||
{
|
||||
for (Class<?> clazz : c)
|
||||
{
|
||||
if (Endpoint.class.isAssignableFrom(clazz))
|
||||
{
|
||||
discovered.addExtendedEndpoint((Class<? extends Endpoint>)clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +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.server.deploy;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* Once an Annotated Server Endpoint is discovered, add it to the list of
|
||||
* discovered Annotated Endpoints.
|
||||
*/
|
||||
public class ServerEndpointAnnotation extends DiscoveredAnnotation
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ServerEndpointAnnotation.class);
|
||||
|
||||
public ServerEndpointAnnotation(WebAppContext context, String className)
|
||||
{
|
||||
super(context,className);
|
||||
}
|
||||
|
||||
public ServerEndpointAnnotation(WebAppContext context, String className, Resource resource)
|
||||
{
|
||||
super(context,className,resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply()
|
||||
{
|
||||
Class<?> clazz = getTargetClass();
|
||||
|
||||
if (clazz == null)
|
||||
{
|
||||
LOG.warn(_className + " cannot be loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
DiscoveredEndpoints discovered = (DiscoveredEndpoints)_context.getAttribute(DiscoveredEndpoints.class.getName());
|
||||
if(discovered == null) {
|
||||
LOG.warn("Context attribute not found: " + DiscoveredEndpoints.class.getName());
|
||||
return;
|
||||
}
|
||||
|
||||
discovered.addAnnotatedEndpoint(clazz);
|
||||
}
|
||||
}
|
|
@ -1,68 +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.server.deploy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
|
||||
import org.eclipse.jetty.annotations.AnnotationParser.ClassInfo;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.webapp.DiscoveredAnnotation;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
/**
|
||||
* Processing for @{@link ServerEndpoint} annotations during Web App Annotation Scanning
|
||||
*/
|
||||
public class ServerEndpointAnnotationHandler extends AbstractDiscoverableAnnotationHandler
|
||||
{
|
||||
private static final String ANNOTATION_NAME = "javax.websocket.server.ServerEndpoint";
|
||||
private static final Logger LOG = Log.getLogger(ServerEndpointAnnotationHandler.class);
|
||||
|
||||
public ServerEndpointAnnotationHandler(WebAppContext context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
public ServerEndpointAnnotationHandler(WebAppContext context, List<DiscoveredAnnotation> list)
|
||||
{
|
||||
super(context,list);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void handle(ClassInfo info, String annotationName)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("handleClass: {}, {}, {}",info.getClassName(),annotationName);
|
||||
}
|
||||
|
||||
if (!ANNOTATION_NAME.equals(annotationName))
|
||||
{
|
||||
// Not the one we are interested in
|
||||
return;
|
||||
}
|
||||
|
||||
ServerEndpointAnnotation annotation = new ServerEndpointAnnotation(_context,info.getClassName(),info.getContainingResource());
|
||||
addAnnotation(annotation);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.deploy;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContainerInitializer;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.HandlesTypes;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.server.ServerApplicationConfig;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter;
|
||||
|
||||
@HandlesTypes(
|
||||
{ ServerApplicationConfig.class, ServerEndpoint.class, Endpoint.class })
|
||||
public class WebSocketServerContainerInitializer implements ServletContainerInitializer
|
||||
{
|
||||
public static final String ENABLE_KEY = "org.eclipse.jetty.websocket.jsr356";
|
||||
private static final Logger LOG = Log.getLogger(WebSocketServerContainerInitializer.class);
|
||||
|
||||
public static boolean isJSR356EnabledOnContext(ServletContext context)
|
||||
{
|
||||
Object enable = context.getAttribute(ENABLE_KEY);
|
||||
if (enable instanceof Boolean)
|
||||
{
|
||||
return ((Boolean)enable).booleanValue();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ServerContainer configureContext(ServletContextHandler context)
|
||||
{
|
||||
// Create Filter
|
||||
WebSocketUpgradeFilter filter = WebSocketUpgradeFilter.configureContext(context);
|
||||
|
||||
// Store reference to the WebSocketUpgradeFilter
|
||||
context.setAttribute(WebSocketUpgradeFilter.class.getName(),filter);
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
ServerContainer jettyContainer = new ServerContainer(filter,filter.getFactory());
|
||||
context.addBean(jettyContainer);
|
||||
|
||||
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
|
||||
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
|
||||
|
||||
return jettyContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartup(Set<Class<?>> c, ServletContext context) throws ServletException
|
||||
{
|
||||
if (!isJSR356EnabledOnContext(context))
|
||||
{
|
||||
LOG.info("JSR-356 support disabled via attribute on context {} - {}",context.getContextPath(),context);
|
||||
return;
|
||||
}
|
||||
|
||||
ContextHandler handler = ContextHandler.getContextHandler(context);
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
throw new ServletException("Not running on Jetty, JSR support disabled");
|
||||
}
|
||||
|
||||
if (!(handler instanceof ServletContextHandler))
|
||||
{
|
||||
throw new ServletException("Not running in Jetty ServletContextHandler, JSR support disabled");
|
||||
}
|
||||
|
||||
ServletContextHandler jettyContext = (ServletContextHandler)handler;
|
||||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
ServerContainer jettyContainer = configureContext(jettyContext);
|
||||
|
||||
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
|
||||
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
|
||||
|
||||
LOG.debug("Found {} classes",c.size());
|
||||
|
||||
// Now process the incoming classes
|
||||
Set<Class<? extends Endpoint>> discoveredExtendedEndpoints = new HashSet<>();
|
||||
Set<Class<?>> discoveredAnnotatedEndpoints = new HashSet<>();
|
||||
Set<Class<? extends ServerApplicationConfig>> serverAppConfigs = new HashSet<>();
|
||||
|
||||
filterClasses(c,discoveredExtendedEndpoints,discoveredAnnotatedEndpoints,serverAppConfigs);
|
||||
|
||||
LOG.debug("Discovered {} extends Endpoint classes",discoveredExtendedEndpoints.size());
|
||||
LOG.debug("Discovered {} @ServerEndpoint classes",discoveredAnnotatedEndpoints.size());
|
||||
LOG.debug("Discovered {} ServerApplicationConfig classes",serverAppConfigs.size());
|
||||
|
||||
// Process the server app configs to determine endpoint filtering
|
||||
boolean wasFiltered = false;
|
||||
Set<ServerEndpointConfig> deployableExtendedEndpointConfigs = new HashSet<>();
|
||||
Set<Class<?>> deployableAnnotatedEndpoints = new HashSet<>();
|
||||
|
||||
for (Class<? extends ServerApplicationConfig> clazz : serverAppConfigs)
|
||||
{
|
||||
LOG.debug("Found ServerApplicationConfig: {}",clazz);
|
||||
try
|
||||
{
|
||||
ServerApplicationConfig config = (ServerApplicationConfig)clazz.newInstance();
|
||||
|
||||
Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints);
|
||||
if (seconfigs != null)
|
||||
{
|
||||
wasFiltered = true;
|
||||
deployableExtendedEndpointConfigs.addAll(seconfigs);
|
||||
}
|
||||
|
||||
Set<Class<?>> annotatedClasses = config.getAnnotatedEndpointClasses(discoveredAnnotatedEndpoints);
|
||||
if (annotatedClasses != null)
|
||||
{
|
||||
wasFiltered = true;
|
||||
deployableAnnotatedEndpoints.addAll(annotatedClasses);
|
||||
}
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
|
||||
}
|
||||
}
|
||||
|
||||
// Default behavior if nothing filtered
|
||||
if (!wasFiltered)
|
||||
{
|
||||
deployableAnnotatedEndpoints.addAll(discoveredAnnotatedEndpoints);
|
||||
// Note: it is impossible to determine path of "extends Endpoint" discovered classes
|
||||
deployableExtendedEndpointConfigs = new HashSet<>();
|
||||
}
|
||||
|
||||
// Deploy what should be deployed.
|
||||
LOG.debug("Deploying {} ServerEndpointConfig(s)",deployableExtendedEndpointConfigs.size());
|
||||
for (ServerEndpointConfig config : deployableExtendedEndpointConfigs)
|
||||
{
|
||||
try
|
||||
{
|
||||
jettyContainer.addEndpoint(config);
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.debug("Deploying {} @ServerEndpoint(s)",deployableAnnotatedEndpoints.size());
|
||||
for (Class<?> annotatedClass : deployableAnnotatedEndpoints)
|
||||
{
|
||||
try
|
||||
{
|
||||
jettyContainer.addEndpoint(annotatedClass);
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void filterClasses(Set<Class<?>> c, Set<Class<? extends Endpoint>> discoveredExtendedEndpoints, Set<Class<?>> discoveredAnnotatedEndpoints,
|
||||
Set<Class<? extends ServerApplicationConfig>> serverAppConfigs)
|
||||
{
|
||||
for (Class<?> clazz : c)
|
||||
{
|
||||
if (ServerApplicationConfig.class.isAssignableFrom(clazz))
|
||||
{
|
||||
serverAppConfigs.add((Class<? extends ServerApplicationConfig>)clazz);
|
||||
}
|
||||
|
||||
if (Endpoint.class.isAssignableFrom(clazz))
|
||||
{
|
||||
discoveredExtendedEndpoints.add((Class<? extends Endpoint>)clazz);
|
||||
}
|
||||
|
||||
ServerEndpoint endpoint = clazz.getAnnotation(ServerEndpoint.class);
|
||||
|
||||
if (endpoint != null)
|
||||
{
|
||||
discoveredAnnotatedEndpoints.add(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
org.eclipse.jetty.websocket.jsr356.server.deploy.ServerApplicationConfigListener
|
||||
org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer
|
|
@ -45,6 +45,7 @@ import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
|||
import org.eclipse.jetty.websocket.jsr356.server.blockhead.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.blockhead.HttpResponse;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.blockhead.IncomingFramesCapture;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -144,7 +145,7 @@ public class ConfiguratorTest
|
|||
context.setContextPath("/");
|
||||
server.setHandler(context);
|
||||
|
||||
ServerContainer container = WebSocketConfiguration.configureContext(context);
|
||||
ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
|
||||
container.addEndpoint(CaptureHeadersSocket.class);
|
||||
container.addEndpoint(EmptySocket.class);
|
||||
container.addEndpoint(NoExtensionsSocket.class);
|
||||
|
|
|
@ -113,7 +113,6 @@ public class WSServer
|
|||
|
||||
// @formatter:off
|
||||
context.setConfigurations(new Configuration[] {
|
||||
new WebSocketConfiguration(),
|
||||
new AnnotationConfiguration(),
|
||||
new WebXmlConfiguration(),
|
||||
new WebInfConfiguration(),
|
||||
|
|
|
@ -60,6 +60,7 @@ public class BlockheadClientConstructionTest
|
|||
this.expectedHttpUri = URI.create(httpuri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@Test
|
||||
public void testURIs() throws URISyntaxException
|
||||
{
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.ServerContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.WebSocketConfiguration;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
|
||||
/**
|
||||
* Tool to help debug JSR based websocket circumstances reported around browsers.
|
||||
|
@ -89,7 +89,7 @@ public class JsrBrowserDebugTool
|
|||
holder.setInitParameter("dirAllowed","true");
|
||||
server.setHandler(context);
|
||||
|
||||
ServerContainer container = WebSocketConfiguration.configureContext(context);
|
||||
ServerContainer container = WebSocketServerContainerInitializer.configureContext(context);
|
||||
container.addEndpoint(JsrBrowserSocket.class);
|
||||
|
||||
LOG.info("{} setup on port {}",this.getClass().getName(),port);
|
||||
|
|
|
@ -1,57 +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.server.deploy;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DiscoveredEndpointsTest
|
||||
{
|
||||
/**
|
||||
* Attempt to get an Archive URI, to a class known to be in an archive.
|
||||
*/
|
||||
@Test
|
||||
public void testGetArchiveURI_InJar()
|
||||
{
|
||||
Class<?> clazz = javax.websocket.server.ServerContainer.class;
|
||||
URI archiveURI = DiscoveredEndpoints.getArchiveURI(clazz);
|
||||
// should point to a JAR file
|
||||
Assert.assertThat("Archive URI for: " + clazz.getName(),
|
||||
archiveURI.toASCIIString(),
|
||||
endsWith("javax.websocket-api-1.0.jar"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an Archive URI for a class reference that is known to not be in an archive.
|
||||
*/
|
||||
@Test
|
||||
public void testGetArchiveURI_InClassDirectory()
|
||||
{
|
||||
Class<?> clazz = DiscoveredEndpointsTest.class;
|
||||
URI archivePath = DiscoveredEndpoints.getArchiveURI(clazz);
|
||||
// Should be null, as it does not point to an archive
|
||||
Assert.assertThat("Archive URI for: " + clazz,
|
||||
archivePath,
|
||||
nullValue());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue