diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java index 0cc7ad4674b..d1e628f7e57 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java @@ -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); diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml index d86f16134d3..ed53786bc56 100644 --- a/jetty-websocket/javax-websocket-server-impl/pom.xml +++ b/jetty-websocket/javax-websocket-server-impl/pom.xml @@ -19,6 +19,7 @@ org.eclipse.jetty jetty-annotations ${project.version} + test org.eclipse.jetty.websocket diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/WebSocketConfiguration.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/WebSocketConfiguration.java deleted file mode 100644 index 1525dadd32a..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/WebSocketConfiguration.java +++ /dev/null @@ -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. - *

- * This configuration will configure a context for JSR356 Websockets. - *

- * It is possible to disable specific contexts with an attribute "org.eclipse.jetty.websocket.jsr356" (set to "false") - *

- * 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. - *

- * 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); - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/DiscoveredEndpoints.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/DiscoveredEndpoints.java deleted file mode 100644 index 124d78159df..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/DiscoveredEndpoints.java +++ /dev/null @@ -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. - *

- * 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 extendedEndpoints; - - private Set annotatedEndpoints; - - public DiscoveredEndpoints() - { - extendedEndpoints = new HashSet<>(); - annotatedEndpoints = new HashSet<>(); - } - - public void addAnnotatedEndpoint(Class endpoint) - { - this.annotatedEndpoints.add(new LocatedClass(endpoint)); - } - - public void addExtendedEndpoint(Class endpoint) - { - this.extendedEndpoints.add(new LocatedClass(endpoint)); - } - - public Set> getAnnotatedEndpoints() - { - Set> endpoints = new HashSet<>(); - for (LocatedClass lc : annotatedEndpoints) - { - endpoints.add(lc.clazz); - } - return endpoints; - } - - public void getArchiveSpecificAnnnotatedEndpoints(URI archiveURI, Set> 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> archiveSpecificEndpoints) - { - for (LocatedClass lc : extendedEndpoints) - { - if ((archiveURI == null) || (lc.location.getPath().equals(archiveURI.getPath()) && Endpoint.class.isAssignableFrom(lc.clazz))) - { - archiveSpecificEndpoints.add((Class)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(); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerApplicationConfigListener.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerApplicationConfigListener.java deleted file mode 100644 index 43464926afa..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerApplicationConfigListener.java +++ /dev/null @@ -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> 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> archiveSpecificExtendEndpoints = new HashSet<>(); - Set> archiveSpecificAnnotatedEndpoints = new HashSet<>(); - List> serverAppConfigs = filterServerApplicationConfigs(c); - - if(serverAppConfigs.size() >= 1) { - for (Class 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 seconfigs = config.getEndpointConfigs(archiveSpecificExtendEndpoints); - if (seconfigs != null) - { - for (ServerEndpointConfig sec : seconfigs) - { - container.addEndpoint(sec); - } - } - Set> 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> filterServerApplicationConfigs(Set> c) - { - List> configs = new ArrayList<>(); - for (Class clazz : c) - { - if (ServerApplicationConfig.class.isAssignableFrom(clazz)) - { - configs.add((Class)clazz); - } - } - return configs; - } - - @SuppressWarnings("unchecked") - private void addEndpoints(Set> c, DiscoveredEndpoints discovered) - { - for (Class clazz : c) - { - if (Endpoint.class.isAssignableFrom(clazz)) - { - discovered.addExtendedEndpoint((Class)clazz); - } - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerEndpointAnnotation.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerEndpointAnnotation.java deleted file mode 100644 index a0ba33c8d4e..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerEndpointAnnotation.java +++ /dev/null @@ -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); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerEndpointAnnotationHandler.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerEndpointAnnotationHandler.java deleted file mode 100644 index eaf49dd826f..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/ServerEndpointAnnotationHandler.java +++ /dev/null @@ -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 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); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java new file mode 100644 index 00000000000..d198649c1e8 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/deploy/WebSocketServerContainerInitializer.java @@ -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> 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> discoveredExtendedEndpoints = new HashSet<>(); + Set> discoveredAnnotatedEndpoints = new HashSet<>(); + Set> 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 deployableExtendedEndpointConfigs = new HashSet<>(); + Set> deployableAnnotatedEndpoints = new HashSet<>(); + + for (Class clazz : serverAppConfigs) + { + LOG.debug("Found ServerApplicationConfig: {}",clazz); + try + { + ServerApplicationConfig config = (ServerApplicationConfig)clazz.newInstance(); + + Set seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints); + if (seconfigs != null) + { + wasFiltered = true; + deployableExtendedEndpointConfigs.addAll(seconfigs); + } + + Set> 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> c, Set> discoveredExtendedEndpoints, Set> discoveredAnnotatedEndpoints, + Set> serverAppConfigs) + { + for (Class clazz : c) + { + if (ServerApplicationConfig.class.isAssignableFrom(clazz)) + { + serverAppConfigs.add((Class)clazz); + } + + if (Endpoint.class.isAssignableFrom(clazz)) + { + discoveredExtendedEndpoints.add((Class)clazz); + } + + ServerEndpoint endpoint = clazz.getAnnotation(ServerEndpoint.class); + + if (endpoint != null) + { + discoveredAnnotatedEndpoints.add(clazz); + } + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer index fd1c3cbca29..0ee5657c562 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer +++ b/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer @@ -1 +1 @@ -org.eclipse.jetty.websocket.jsr356.server.deploy.ServerApplicationConfigListener \ No newline at end of file +org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer \ No newline at end of file diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java index dae78b6cde6..46e40bc58aa 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/ConfiguratorTest.java @@ -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); diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java index 108099af205..13b5631467d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/WSServer.java @@ -113,7 +113,6 @@ public class WSServer // @formatter:off context.setConfigurations(new Configuration[] { - new WebSocketConfiguration(), new AnnotationConfiguration(), new WebXmlConfiguration(), new WebInfConfiguration(), diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClientConstructionTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClientConstructionTest.java index a88ed7ca680..1eba239fa8f 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClientConstructionTest.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/blockhead/BlockheadClientConstructionTest.java @@ -60,6 +60,7 @@ public class BlockheadClientConstructionTest this.expectedHttpUri = URI.create(httpuri); } + @SuppressWarnings("resource") @Test public void testURIs() throws URISyntaxException { diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserDebugTool.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserDebugTool.java index ae91e49b770..4ecd2899bee 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserDebugTool.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/browser/JsrBrowserDebugTool.java @@ -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); diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/deploy/DiscoveredEndpointsTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/deploy/DiscoveredEndpointsTest.java deleted file mode 100644 index 3bcaf075b82..00000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/deploy/DiscoveredEndpointsTest.java +++ /dev/null @@ -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()); - } -}