diff options
author | Joakim Erdfelt | 2013-04-23 18:06:01 +0000 |
---|---|---|
committer | Joakim Erdfelt | 2013-04-23 18:06:01 +0000 |
commit | a4644dc78008dab958895ba87fe2f6a99aea909b (patch) | |
tree | 5cbfe85fd6757904db5f887ea4ca3cbc5959a1d9 /jetty-websocket/javax-websocket-server-impl | |
parent | 346034b44fe42af7c592c138347c0dabbb124f2a (diff) | |
download | org.eclipse.jetty.project-a4644dc78008dab958895ba87fe2f6a99aea909b.tar.gz org.eclipse.jetty.project-a4644dc78008dab958895ba87fe2f6a99aea909b.tar.xz org.eclipse.jetty.project-a4644dc78008dab958895ba87fe2f6a99aea909b.zip |
JSR-356 working out server endpoint creation
Diffstat (limited to 'jetty-websocket/javax-websocket-server-impl')
31 files changed, 792 insertions, 1446 deletions
diff --git a/jetty-websocket/javax-websocket-server-impl/pom.xml b/jetty-websocket/javax-websocket-server-impl/pom.xml index cfd8c918a5..bf4dabe388 100644 --- a/jetty-websocket/javax-websocket-server-impl/pom.xml +++ b/jetty-websocket/javax-websocket-server-impl/pom.xml @@ -27,9 +27,14 @@ <version>${project.version}</version> </dependency> <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>websocket-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.eclipse.jetty.drafts</groupId> <artifactId>javax.websocket-api</artifactId> - <version>1.0.0.PFD-SNAPSHOT</version> + <version>1.0.0.DRAFT-SNAPSHOT</version> </dependency> <dependency> <groupId>org.eclipse.jetty.toolchain</groupId> diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfigurator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfigurator.java new file mode 100644 index 0000000000..65de4b5960 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfigurator.java @@ -0,0 +1,60 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server; + +import java.util.List; + +import javax.websocket.Extension; +import javax.websocket.HandshakeResponse; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerEndpointConfig; +import javax.websocket.server.ServerEndpointConfig.Configurator; + +public class JettyServerEndpointConfigurator extends Configurator +{ + @Override + public boolean checkOrigin(String originHeaderValue) + { + return super.checkOrigin(originHeaderValue); + } + + @Override + public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException + { + return super.getEndpointInstance(endpointClass); + } + + @Override + public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested) + { + return super.getNegotiatedExtensions(installed,requested); + } + + @Override + public String getNegotiatedSubprotocol(List<String> supported, List<String> requested) + { + return super.getNegotiatedSubprotocol(supported,requested); + } + + @Override + public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) + { + super.modifyHandshake(sec,request,response); + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java new file mode 100644 index 0000000000..0a1d491a7b --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrCreator.java @@ -0,0 +1,93 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server; + +import java.io.IOException; +import java.util.List; + +import javax.websocket.server.ServerEndpointConfig; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.websocket.api.UpgradeRequest; +import org.eclipse.jetty.websocket.api.UpgradeResponse; +import org.eclipse.jetty.websocket.servlet.WebSocketCreator; + +public class JsrCreator implements WebSocketCreator +{ + private static final Logger LOG = Log.getLogger(JsrCreator.class); + private final ServerEndpointConfig config; + + public JsrCreator(ServerEndpointConfig config) + { + this.config = config; + } + + @Override + public Object createWebSocket(UpgradeRequest req, UpgradeResponse resp) + { + JsrHandshakeRequest hsreq = new JsrHandshakeRequest(req); + JsrHandshakeResponse hsresp = new JsrHandshakeResponse(resp); + + ServerEndpointConfig.Configurator configurator = config.getConfigurator(); + + // modify handshake + configurator.modifyHandshake(config,hsreq,hsresp); + + // check origin + if (!configurator.checkOrigin(req.getOrigin())) + { + try + { + resp.sendForbidden("Origin mismatch"); + } + catch (IOException e) + { + LOG.debug("Unable to send error response",e); + } + return null; + } + + // deal with sub protocols + List<String> supported = config.getSubprotocols(); + List<String> requested = req.getSubProtocols(); + String subprotocol = configurator.getNegotiatedSubprotocol(supported,requested); + if (subprotocol != null) + { + resp.setAcceptedSubProtocol(subprotocol); + } + + // create endpoint class + try + { + return config.getEndpointClass().newInstance(); + } + catch (InstantiationException | IllegalAccessException e) + { + LOG.debug("Unable to create websocket: " + config.getEndpointClass().getName(),e); + return null; + } + } + + @Override + public String toString() + { + return String.format("%s[config=%s]",this.getClass().getName(),config); + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java new file mode 100644 index 0000000000..f1b0a70681 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeRequest.java @@ -0,0 +1,83 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server; + +import java.net.URI; +import java.security.Principal; +import java.util.List; +import java.util.Map; + +import javax.websocket.server.HandshakeRequest; + +import org.eclipse.jetty.websocket.api.UpgradeRequest; + +public class JsrHandshakeRequest implements HandshakeRequest +{ + private final UpgradeRequest request; + + public JsrHandshakeRequest(UpgradeRequest req) + { + this.request = req; + } + + @Override + public Map<String, List<String>> getHeaders() + { + return request.getHeaders(); + } + + @Override + public Object getHttpSession() + { + return request.getSession(); + } + + @Override + public Map<String, List<String>> getParameterMap() + { + return request.getParameterMap(); + } + + @Override + public String getQueryString() + { + return request.getQueryString(); + } + + @Override + public URI getRequestURI() + { + return request.getRequestURI(); + } + + @Override + public Principal getUserPrincipal() + { + // TODO: need to return User Principal + return null; + } + + @Override + public boolean isUserInRole(String role) + { + // TODO: need to return isUserInRole result + return false; + } + +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/WebSocketHandler.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeResponse.java index 7ba75d1176..0eaf62f3ee 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/WebSocketHandler.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrHandshakeResponse.java @@ -18,8 +18,25 @@ package org.eclipse.jetty.websocket.jsr356.server; -import org.eclipse.jetty.server.handler.HandlerWrapper; +import java.util.List; +import java.util.Map; -public class WebSocketHandler extends HandlerWrapper +import javax.websocket.HandshakeResponse; + +import org.eclipse.jetty.websocket.api.UpgradeResponse; + +public class JsrHandshakeResponse implements HandshakeResponse { + private final UpgradeResponse response; + + public JsrHandshakeResponse(UpgradeResponse resp) + { + this.response = resp; + } + + @Override + public Map<String, List<String>> getHeaders() + { + return response.getHeaders(); + } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrServerMetadata.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrServerMetadata.java index 71bf546769..13b9f1279d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrServerMetadata.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/JsrServerMetadata.java @@ -106,4 +106,9 @@ public class JsrServerMetadata extends JsrMetadata<ServerEndpoint> // Copy constructor return new JettyServerEndpointConfig(config); } + + public String getPath() + { + return config.getPath(); + } } diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java index 37ee61dc70..02336accf2 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/ServerContainer.java @@ -18,33 +18,78 @@ package org.eclipse.jetty.websocket.jsr356.server; +import java.util.EnumSet; import java.util.concurrent.ConcurrentHashMap; +import javax.servlet.DispatcherType; +import javax.websocket.ContainerProvider; import javax.websocket.DeploymentException; import javax.websocket.server.ServerEndpointConfig; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.websocket.jsr356.ClientContainer; import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner; +import org.eclipse.jetty.websocket.jsr356.server.pathmap.WebSocketPathSpec; +import org.eclipse.jetty.websocket.server.MappedWebSocketCreator; +import org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter; public class ServerContainer extends ClientContainer implements javax.websocket.server.ServerContainer { + private static final Logger LOG = Log.getLogger(ServerContainer.class); + + public static ServerContainer getInstance() + { + return (ServerContainer)ContainerProvider.getWebSocketContainer(); + } private ConcurrentHashMap<Class<?>, JsrServerMetadata> endpointServerMetadataCache = new ConcurrentHashMap<>(); + private MappedWebSocketCreator mappedCreator; + + public ServerContainer() + { + super(); + WebAppContext webapp = WebAppContext.getCurrentWebAppContext(); + if (webapp != null) + { + WebSocketUpgradeFilter filter = new WebSocketUpgradeFilter(); + FilterHolder fholder = new FilterHolder(filter); + fholder.setName("Jetty_WebSocketUpgradeFilter"); + fholder.setDisplayName("WebSocket Upgrade Filter"); + String pathSpec = "/*"; + webapp.addFilter(fholder,pathSpec,EnumSet.of(DispatcherType.REQUEST)); + LOG.debug("Adding {} mapped to {} to {}",filter,pathSpec,webapp); + mappedCreator = filter; + } + else + { + LOG.debug("No active WebAppContext detected"); + } + } @Override public void addEndpoint(Class<?> endpointClass) throws DeploymentException { - // TODO Auto-generated method stub + JsrServerMetadata metadata = getServerEndpointMetadata(endpointClass); + addEndpoint(metadata); } - public void addEndpoint(JsrServerMetadata metadata) + public void addEndpoint(JsrServerMetadata metadata) throws DeploymentException { - // TODO Auto-generated method stub + addEndpoint(metadata.getEndpointConfigCopy()); } @Override - public void addEndpoint(ServerEndpointConfig serverConfig) throws DeploymentException + public void addEndpoint(ServerEndpointConfig config) throws DeploymentException + { + JsrCreator creator = new JsrCreator(config); + mappedCreator.addMapping(new WebSocketPathSpec(config.getPath()),creator); + } + + public void addMappedCreator(MappedWebSocketCreator mappedCreator) { - // TODO Auto-generated method stub + this.mappedCreator = mappedCreator; } public JsrServerMetadata getServerEndpointMetadata(Class<?> endpointClass) throws DeploymentException diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappings.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappings.java deleted file mode 100644 index bb737afb5c..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappings.java +++ /dev/null @@ -1,147 +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.pathmap; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import org.eclipse.jetty.websocket.jsr356.server.pathmap.PathMappings.MappedResource; - -/** - * Path Mappings of PathSpec to Resource. - * <p> - * Sorted into search order upon entry into the Set - * - * @param <E> - */ -public class PathMappings<E> implements Iterable<MappedResource<E>> -{ - public static class MappedResource<E> implements Comparable<MappedResource<E>> - { - private final PathSpec pathSpec; - private final E resource; - - public MappedResource(PathSpec pathSpec, E resource) - { - this.pathSpec = pathSpec; - this.resource = resource; - } - - /** - * Comparison is based solely on the pathSpec - */ - @Override - public int compareTo(MappedResource<E> other) - { - return this.pathSpec.compareTo(other.pathSpec); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - MappedResource<?> other = (MappedResource<?>)obj; - if (pathSpec == null) - { - if (other.pathSpec != null) - { - return false; - } - } - else if (!pathSpec.equals(other.pathSpec)) - { - return false; - } - return true; - } - - public PathSpec getPathSpec() - { - return pathSpec; - } - - public E getResource() - { - return resource; - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode()); - return result; - } - - @Override - public String toString() - { - return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource); - } - } - - private List<MappedResource<E>> mappings = new ArrayList<MappedResource<E>>(); - private MappedResource<E> defaultResource = null; - - public MappedResource<E> getMatch(String path) - { - int len = mappings.size(); - for (int i = 0; i < len; i++) - { - MappedResource<E> mr = mappings.get(i); - if (mr.getPathSpec().matches(path)) - { - return mr; - } - } - return defaultResource; - } - - @Override - public Iterator<MappedResource<E>> iterator() - { - return mappings.iterator(); - } - - public void put(PathSpec pathSpec, E resource) - { - MappedResource<E> entry = new MappedResource<>(pathSpec,resource); - if (pathSpec.group == PathSpecGroup.DEFAULT) - { - defaultResource = entry; - } - // TODO: warning on replacement of existing mapping? - mappings.add(entry); - Collections.sort(mappings); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathSpec.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathSpec.java deleted file mode 100644 index 2a8fb67776..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathSpec.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.pathmap; - -/** - * The base PathSpec, what all other path specs are based on - */ -public abstract class PathSpec implements Comparable<PathSpec> -{ - protected String pathSpec; - protected PathSpecGroup group; - protected int pathDepth; - protected int specLength; - - @Override - public int compareTo(PathSpec other) - { - // Grouping (increasing) - int diff = this.group.ordinal() - other.group.ordinal(); - if (diff != 0) - { - return diff; - } - - // Spec Length (decreasing) - diff = other.specLength - this.specLength; - if (diff != 0) - { - return diff; - } - - // Path Spec Name (alphabetical) - return this.pathSpec.compareTo(other.pathSpec); - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - PathSpec other = (PathSpec)obj; - if (pathSpec == null) - { - if (other.pathSpec != null) - { - return false; - } - } - else if (!pathSpec.equals(other.pathSpec)) - { - return false; - } - return true; - } - - /** - * Get the number of path elements that this path spec declares. - * <p> - * This is used to determine longest match logic. - * - * @return the depth of the path segments that this spec declares - */ - public int getPathDepth() - { - return pathDepth; - } - - /** - * Return the portion of the path that is after the path spec. - * - * @param path - * the path to match against - * @return the path info portion of the string - */ - public abstract String getPathInfo(String path); - - /** - * Return the portion of the path that matches a path spec. - * - * @param path - * the path to match against - * @return the match, or null if no match at all - */ - public abstract String getPathMatch(String path); - - /** - * The as-provided path spec. - * - * @return the as-provided path spec - */ - public String getPathSpec() - { - return pathSpec; - } - - /** - * Get the relative path. - * - * @param base - * the base the path is relative to - * @param path - * the additional path - * @return the base plus path with pathSpec portion removed - */ - public abstract String getRelativePath(String base, String path); - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode()); - return result; - } - - /** - * Test to see if the provided path matches this path spec - * - * @param path - * the path to test - * @return true if the path matches this path spec, false otherwise - */ - public abstract boolean matches(String path); - - @Override - public String toString() - { - StringBuilder str = new StringBuilder(); - str.append(this.getClass().getSimpleName()).append("[\""); - str.append(pathSpec); - str.append("\",pathDepth=").append(pathDepth); - str.append(",group=").append(group); - str.append("]"); - return str.toString(); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathSpecGroup.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathSpecGroup.java deleted file mode 100644 index 91eae4eec3..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathSpecGroup.java +++ /dev/null @@ -1,82 +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.pathmap; - -/** - * Types of path spec groups. - * <p> - * This is used to facilitate proper pathspec search order. - * <p> - * Search Order: {@link PathSpecGroup#ordinal()} [increasin], {@link PathSpec#specLength} [decreasing], {@link PathSpec#pathSpec} [natural sort order] - */ -public enum PathSpecGroup -{ - // NOTE: Order of enums determines order of Groups. - - /** - * For exactly defined path specs, no glob. - */ - EXACT, - /** - * For path specs that have a hardcoded prefix and suffix with wildcard glob in the middle. - * - * <pre> - * "^/downloads/[^/]*.zip$" - regex spec - * "/a/{var}/c" - websocket spec - * </pre> - * - * Note: there is no known servlet spec variant of this kind of path spec - */ - MIDDLE_GLOB, - /** - * For path specs that have a hardcoded prefix and a trailing wildcard glob. - * <p> - * - * <pre> - * "/downloads/*" - servlet spec - * "/api/*" - servlet spec - * "^/rest/.*$" - regex spec - * "/bookings/{guest-id}" - websocket spec - * "/rewards/{vip-level}" - websocket spec - * </pre> - */ - PREFIX_GLOB, - /** - * For path specs that have a wildcard glob with a hardcoded suffix - * - * <pre> - * "*.do" - servlet spec - * "*.css" - servlet spec - * "^.*\.zip$" - regex spec - * </pre> - * - * Note: there is no known websocket spec variant of this kind of path spec - */ - SUFFIX_GLOB, - /** - * The default spec for accessing the Root and/or Default behavior. - * - * <pre> - * "/" - servlet spec (Default Servlet) - * "/" - websocket spec (Root Context) - * "^/$" - regex spec (Root Context) - * </pre> - */ - DEFAULT; -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/RegexPathSpec.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/RegexPathSpec.java deleted file mode 100644 index 6452958a80..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/RegexPathSpec.java +++ /dev/null @@ -1,166 +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.pathmap; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class RegexPathSpec extends PathSpec -{ - protected Pattern pattern; - - protected RegexPathSpec() - { - super(); - } - - public RegexPathSpec(String regex) - { - super.pathSpec = regex; - boolean inGrouping = false; - this.pathDepth = 0; - this.specLength = pathSpec.length(); - // build up a simple signature we can use to identify the grouping - StringBuilder signature = new StringBuilder(); - for (char c : pathSpec.toCharArray()) - { - switch (c) - { - case '[': - inGrouping = true; - break; - case ']': - inGrouping = false; - signature.append('g'); // glob - break; - case '*': - signature.append('g'); // glob - break; - case '/': - if (!inGrouping) - { - this.pathDepth++; - } - break; - default: - if (!inGrouping) - { - if (Character.isLetterOrDigit(c)) - { - signature.append('l'); // literal (exact) - } - } - break; - } - } - this.pattern = Pattern.compile(pathSpec); - - // Figure out the grouping based on the signature - String sig = signature.toString(); - - if (Pattern.matches("^l*$",sig)) - { - this.group = PathSpecGroup.EXACT; - } - else if (Pattern.matches("^l*g+",sig)) - { - this.group = PathSpecGroup.PREFIX_GLOB; - } - else if (Pattern.matches("^g+l+$",sig)) - { - this.group = PathSpecGroup.SUFFIX_GLOB; - } - else - { - this.group = PathSpecGroup.MIDDLE_GLOB; - } - } - - public Matcher getMatcher(String path) - { - return this.pattern.matcher(path); - } - - @Override - public String getPathInfo(String path) - { - // Path Info only valid for PREFIX_GLOB types - if (group == PathSpecGroup.PREFIX_GLOB) - { - Matcher matcher = getMatcher(path); - if (matcher.matches()) - { - if (matcher.groupCount() >= 1) - { - String pathInfo = matcher.group(1); - if ("".equals(pathInfo)) - { - return "/"; - } - else - { - return pathInfo; - } - } - } - } - return null; - } - - @Override - public String getPathMatch(String path) - { - Matcher matcher = getMatcher(path); - if (matcher.matches()) - { - if (matcher.groupCount() >= 1) - { - int idx = matcher.start(1); - if (idx > 0) - { - if (path.charAt(idx - 1) == '/') - { - idx--; - } - return path.substring(0,idx); - } - } - return path; - } - return null; - } - - public Pattern getPattern() - { - return this.pattern; - } - - @Override - public String getRelativePath(String base, String path) - { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean matches(String path) - { - return getMatcher(path).matches(); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/ServletPathSpec.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/ServletPathSpec.java deleted file mode 100644 index 541c85f5c6..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/ServletPathSpec.java +++ /dev/null @@ -1,291 +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.pathmap; - -import org.eclipse.jetty.util.URIUtil; - -public class ServletPathSpec extends PathSpec -{ - public static final String PATH_SPEC_SEPARATORS = ":,"; - - /** - * Get multi-path spec splits. - * - * @param servletPathSpec - * the path spec that might contain multiple declared path specs - * @return the individual path specs found. - */ - public static ServletPathSpec[] getMultiPathSpecs(String servletPathSpec) - { - String pathSpecs[] = servletPathSpec.split(PATH_SPEC_SEPARATORS); - int len = pathSpecs.length; - ServletPathSpec sps[] = new ServletPathSpec[len]; - for (int i = 0; i < len; i++) - { - sps[i] = new ServletPathSpec(pathSpecs[i]); - } - return sps; - } - - public ServletPathSpec(String servletPathSpec) - { - super(); - assertValidServletPathSpec(servletPathSpec); - - // The Path Spec for Default Servlet - if ((servletPathSpec == null) || (servletPathSpec.length() == 0) || "/".equals(servletPathSpec)) - { - super.pathSpec = "/"; - super.pathDepth = -1; // force this to be last in sort order - this.specLength = 1; - this.group = PathSpecGroup.DEFAULT; - return; - } - - this.specLength = servletPathSpec.length(); - super.pathDepth = 0; - char lastChar = servletPathSpec.charAt(specLength - 1); - // prefix based - if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*')) - { - this.group = PathSpecGroup.PREFIX_GLOB; - } - // suffix based - else if (servletPathSpec.charAt(0) == '*') - { - this.group = PathSpecGroup.SUFFIX_GLOB; - } - else - { - this.group = PathSpecGroup.EXACT; - } - - for (int i = 0; i < specLength; i++) - { - int cp = servletPathSpec.codePointAt(i); - if (cp < 128) - { - char c = (char)cp; - switch (c) - { - case '/': - super.pathDepth++; - break; - } - } - } - - super.pathSpec = servletPathSpec; - } - - private void assertValidServletPathSpec(String servletPathSpec) - { - if ((servletPathSpec == null) || servletPathSpec.equals("")) - { - return; // empty path spec - } - - // Ensure we don't have path spec separators here in our single path spec. - for (char c : PATH_SPEC_SEPARATORS.toCharArray()) - { - if (servletPathSpec.indexOf(c) >= 0) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: encountered Path Spec Separator [" + PATH_SPEC_SEPARATORS - + "] within specified path spec. did you forget to split this path spec up?"); - } - } - - int len = servletPathSpec.length(); - // path spec must either start with '/' or '*.' - if (servletPathSpec.charAt(0) == '/') - { - // Prefix Based - if (len == 1) - { - return; // simple '/' path spec - } - int idx = servletPathSpec.indexOf('*'); - if (idx < 0) - { - return; // no hit on glob '*' - } - // only allowed to have '*' at the end of the path spec - if (idx != (len - 1)) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches"); - } - } - else if (servletPathSpec.startsWith("*.")) - { - // Suffix Based - int idx = servletPathSpec.indexOf('/'); - // cannot have path separator - if (idx >= 0) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators"); - } - - idx = servletPathSpec.indexOf('*',2); - // only allowed to have 1 glob '*', at the start of the path spec - if (idx >= 1) - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*'"); - } - } - else - { - throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\""); - } - } - - @Override - public String getPathInfo(String path) - { - // Path Info only valid for PREFIX_GLOB types - if (group == PathSpecGroup.PREFIX_GLOB) - { - if (path.length() == (specLength - 2)) - { - return null; - } - return path.substring(specLength - 2); - } - - return null; - } - - @Override - public String getPathMatch(String path) - { - switch (group) - { - case EXACT: - if (pathSpec.equals(path)) - { - return path; - } - else - { - return null; - } - case PREFIX_GLOB: - if (isWildcardMatch(path)) - { - return path.substring(0,specLength - 2); - } - else - { - return null; - } - case SUFFIX_GLOB: - if (path.regionMatches(path.length() - (specLength - 1),pathSpec,1,specLength - 1)) - { - return path; - } - else - { - return null; - } - case DEFAULT: - return path; - default: - return null; - } - } - - @Override - public String getRelativePath(String base, String path) - { - String info = getPathInfo(path); - if (info == null) - { - info = path; - } - - if (info.startsWith("./")) - { - info = info.substring(2); - } - if (base.endsWith(URIUtil.SLASH)) - { - if (info.startsWith(URIUtil.SLASH)) - { - path = base + info.substring(1); - } - else - { - path = base + info; - } - } - else if (info.startsWith(URIUtil.SLASH)) - { - path = base + info; - } - else - { - path = base + URIUtil.SLASH + info; - } - return path; - } - - private boolean isExactMatch(String path) - { - if (group == PathSpecGroup.EXACT) - { - if (pathSpec.equals(path)) - { - return true; - } - return (path.charAt(path.length() - 1) == '/') && (path.equals(pathSpec + '/')); - } - return false; - } - - private boolean isWildcardMatch(String path) - { - // For a spec of "/foo/*" match "/foo" , "/foo/..." but not "/foobar" - int cpl = specLength - 2; - if ((group == PathSpecGroup.PREFIX_GLOB) && (path.regionMatches(0,pathSpec,0,cpl))) - { - if ((path.length() == cpl) || ('/' == path.charAt(cpl))) - { - return true; - } - } - return false; - } - - @Override - public boolean matches(String path) - { - switch (group) - { - case EXACT: - return isExactMatch(path); - case PREFIX_GLOB: - return isWildcardMatch(path); - case SUFFIX_GLOB: - return path.regionMatches((path.length() - specLength) + 1,pathSpec,1,specLength - 1); - case DEFAULT: - return true; - default: - return false; - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java index 3c136b5727..42c76dcfe6 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java +++ b/jetty-websocket/javax-websocket-server-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpec.java @@ -29,10 +29,14 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; +import org.eclipse.jetty.websocket.server.pathmap.PathSpecGroup; +import org.eclipse.jetty.websocket.server.pathmap.RegexPathSpec; + /** - * PathSpec for WebSocket @{@link ServerEndpoint} declarations. + * PathSpec for WebSocket @{@link ServerEndpoint} declarations with support for URI templates and @{@link PathParam} annotations */ public class WebSocketPathSpec extends RegexPathSpec { diff --git a/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator b/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator new file mode 100644 index 0000000000..34fa1370e8 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/main/resources/META-INF/services/javax.websocket.server.ServerEndpointConfig$Configurator @@ -0,0 +1 @@ +org.eclipse.jetty.websocket.jsr356.server.JettyServerEndpointConfigurator
\ No newline at end of file diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicAnnotatedTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicAnnotatedTest.java index 197f71a5c7..1017c4640c 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicAnnotatedTest.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicAnnotatedTest.java @@ -35,11 +35,14 @@ import org.eclipse.jetty.webapp.WebInfConfiguration; import org.eclipse.jetty.webapp.WebXmlConfiguration; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.eclipse.jetty.websocket.jsr356.server.samples.BasicEchoSocket; +import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoSocket; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; +/** + * Example of an annotated echo server discovered via annotation scanning. + */ public class BasicAnnotatedTest { @Rule diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java new file mode 100644 index 0000000000..411b2b3041 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/BasicEndpointTest.java @@ -0,0 +1,90 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server; + +import java.net.URI; +import java.util.Queue; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import javax.websocket.Endpoint; +import javax.websocket.server.ServerContainer; + +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.websocket.api.Session; +import org.eclipse.jetty.websocket.client.WebSocketClient; +import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoEndpoint; +import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoEndpointConfigContextListener; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +/** + * Example of an {@link Endpoint} extended echo server added programmatically via the + * {@link ServerContainer#addEndpoint(javax.websocket.server.ServerEndpointConfig)} + */ +public class BasicEndpointTest +{ + @Rule + public TestingDir testdir = new TestingDir(); + + @Test + public void testEcho() throws Exception + { + WSServer wsb = new WSServer(testdir,"app"); + wsb.copyWebInf("basic-echo-endpoint-config-web.xml"); + // the endpoint (extends javax.websocket.Endpoint) + wsb.copyClass(BasicEchoEndpoint.class); + // the configuration (adds the endpoint) + wsb.copyClass(BasicEchoEndpointConfigContextListener.class); + + try + { + wsb.start(); + URI uri = wsb.getServerBaseURI(); + + WebAppContext webapp = wsb.createWebAppContext(); + // default webapp configuration used (no annotation scanning) + wsb.deployWebapp(webapp); + wsb.dump(); + + WebSocketClient client = new WebSocketClient(); + try + { + client.start(); + JettyEchoSocket clientEcho = new JettyEchoSocket(); + Future<Session> future = client.connect(clientEcho,uri.resolve("/echo")); + // wait for connect + future.get(1,TimeUnit.SECONDS); + clientEcho.sendMessage("Hello World"); + Queue<String> msgs = clientEcho.awaitMessages(1); + Assert.assertEquals("Expected message","Hello World",msgs.poll()); + } + finally + { + client.stop(); + } + } + finally + { + wsb.stop(); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java new file mode 100644 index 0000000000..55e30f3acc --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/JettyServerEndpointConfiguratorTest.java @@ -0,0 +1,51 @@ +// +// ======================================================================== +// 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 static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.Iterator; +import java.util.ServiceLoader; + +import javax.websocket.server.ServerEndpointConfig; + +import org.junit.Test; + +/** + * Test the JettyServerEndpointConfigurator impl. + */ +public class JettyServerEndpointConfiguratorTest +{ + @Test + public void testServiceLoader() + { + System.out.printf("Service Name: %s%n",ServerEndpointConfig.Configurator.class.getName()); + + ServiceLoader<ServerEndpointConfig.Configurator> loader = ServiceLoader.load(javax.websocket.server.ServerEndpointConfig.Configurator.class); + assertThat("loader",loader,notNullValue()); + Iterator<ServerEndpointConfig.Configurator> iter = loader.iterator(); + assertThat("loader.iterator",iter,notNullValue()); + assertThat("loader.iterator.hasNext",iter.hasNext(),is(true)); + + ServerEndpointConfig.Configurator configr = iter.next(); + assertThat("Configurator",configr,notNullValue()); + assertThat("COnfigurator type",configr,instanceOf(JettyServerEndpointConfigurator.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 3dc2ed997a..baeeff70ed 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 @@ -34,6 +34,8 @@ import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.Assert; @@ -44,6 +46,7 @@ import org.junit.Assert; */ public class WSServer { + private static final Logger LOG = Log.getLogger(WSServer.class); @SuppressWarnings("unused") private final TestingDir testdir; private final File contextDir; @@ -62,18 +65,34 @@ public class WSServer FS.ensureEmpty(contextDir); } - public void copyEndpoint(Class<?> endpointClass) throws Exception + public void copyClass(Class<?> clazz) throws Exception { ClassLoader cl = Thread.currentThread().getContextClassLoader(); - String endpointPath = endpointClass.getName().replace('.','/') + ".class"; + String endpointPath = clazz.getName().replace('.','/') + ".class"; URL classUrl = cl.getResource(endpointPath); - Assert.assertThat("Class URL for: " + endpointClass,classUrl,notNullValue()); + Assert.assertThat("Class URL for: " + clazz,classUrl,notNullValue()); File destFile = new File(classesDir,OS.separators(endpointPath)); FS.ensureDirExists(destFile.getParentFile()); File srcFile = new File(classUrl.toURI()); IO.copy(srcFile,destFile); } + public void copyEndpoint(Class<?> endpointClass) throws Exception + { + copyClass(endpointClass); + } + + public void copyWebInf(String testResourceName) throws IOException + { + webinf = new File(contextDir,"WEB-INF"); + FS.ensureDirExists(webinf); + classesDir = new File(webinf,"classes"); + FS.ensureDirExists(classesDir); + File webxml = new File(webinf,"web.xml"); + File testWebXml = MavenTestingUtils.getTestResourceFile(testResourceName); + IO.copy(testWebXml,webxml); + } + public WebAppContext createWebAppContext() { WebAppContext context = new WebAppContext(); @@ -84,13 +103,7 @@ public class WSServer public void createWebInf() throws IOException { - webinf = new File(contextDir,"WEB-INF"); - FS.ensureDirExists(webinf); - classesDir = new File(webinf,"classes"); - FS.ensureDirExists(classesDir); - File webxml = new File(webinf,"web.xml"); - File emptyWebXml = MavenTestingUtils.getTestResourceFile("empty-web.xml"); - IO.copy(emptyWebXml,webxml); + copyWebInf("empty-web.xml"); } public void deployWebapp(WebAppContext webapp) throws Exception @@ -134,6 +147,7 @@ public class WSServer } int port = connector.getLocalPort(); serverUri = new URI(String.format("ws://%s:%d/",host,port)); + LOG.debug("Server started on {}",serverUri); } public void stop() diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsBenchmarkTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsBenchmarkTest.java deleted file mode 100644 index 250ec30934..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsBenchmarkTest.java +++ /dev/null @@ -1,224 +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.pathmap; - -import java.util.concurrent.CyclicBarrier; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.http.PathMap; -import org.eclipse.jetty.toolchain.test.AdvancedRunner; -import org.eclipse.jetty.toolchain.test.annotation.Stress; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AdvancedRunner.class) -public class PathMappingsBenchmarkTest -{ - public static abstract class AbstractPathMapThread extends Thread - { - private int iterations; - private CyclicBarrier barrier; - private long success; - private long error; - - public AbstractPathMapThread(int iterations, CyclicBarrier barrier) - { - this.iterations = iterations; - this.barrier = barrier; - } - - public abstract String getMatchedResource(String path); - - @Override - public void run() - { - int llen = LOOKUPS.length; - String path; - String expectedResource; - String matchedResource; - await(barrier); - for (int iter = 0; iter < iterations; iter++) - { - for (int li = 0; li < llen; li++) - { - path = LOOKUPS[li][0]; - expectedResource = LOOKUPS[li][1]; - matchedResource = getMatchedResource(path); - if (matchedResource.equals(expectedResource)) - { - success++; - } - else - { - error++; - } - } - } - await(barrier); - } - } - - public static class PathMapMatchThread extends AbstractPathMapThread - { - private PathMap<String> pathmap; - - public PathMapMatchThread(PathMap<String> pathmap, int iters, CyclicBarrier barrier) - { - super(iters,barrier); - this.pathmap = pathmap; - } - - @Override - public String getMatchedResource(String path) - { - return pathmap.getMatch(path).getValue(); - } - } - - public static class PathMatchThread extends AbstractPathMapThread - { - private PathMappings<String> pathmap; - - public PathMatchThread(PathMappings<String> pathmap, int iters, CyclicBarrier barrier) - { - super(iters,barrier); - this.pathmap = pathmap; - } - - @Override - public String getMatchedResource(String path) - { - return pathmap.getMatch(path).getResource(); - } - } - - private static final Logger LOG = Log.getLogger(PathMappingsBenchmarkTest.class); - private static final String[][] LOOKUPS; - private int runs = 20; - private int threads = 200; - private int iters = 10000; - - static - { - LOOKUPS = new String[][] - { - // @formatter:off - { "/abs/path", "path" }, - { "/abs/path/longer","longpath" }, - { "/abs/path/foo","default" }, - { "/main.css","default" }, - { "/downloads/script.gz","gzipped" }, - { "/downloads/distribution.tar.gz","tarball" }, - { "/downloads/readme.txt","default" }, - { "/downloads/logs.tgz","default" }, - { "/animal/horse/mustang","animals" }, - { "/animal/bird/eagle/bald","birds" }, - { "/animal/fish/shark/hammerhead","fishes" }, - { "/animal/insect/ladybug","animals" }, - // @formatter:on - }; - } - - private static void await(CyclicBarrier barrier) - { - try - { - barrier.await(); - } - catch (Exception x) - { - throw new RuntimeException(x); - } - } - - @Stress("High CPU") - @Test - public void testServletPathMap() - { - // Setup (old) PathMap - - PathMap<String> p = new PathMap<>(); - - p.put("/abs/path","path"); - p.put("/abs/path/longer","longpath"); - p.put("/animal/bird/*","birds"); - p.put("/animal/fish/*","fishes"); - p.put("/animal/*","animals"); - p.put("*.tar.gz","tarball"); - p.put("*.gz","gzipped"); - p.put("/","default"); - - final CyclicBarrier barrier = new CyclicBarrier(threads + 1); - - for (int r = 0; r < runs; r++) - { - for (int t = 0; t < threads; t++) - { - PathMapMatchThread thread = new PathMapMatchThread(p,iters,barrier); - thread.start(); - } - await(barrier); - long begin = System.nanoTime(); - await(barrier); - long end = System.nanoTime(); - long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); - int totalMatches = threads * iters * LOOKUPS.length; - LOG.info("jetty-http/PathMap (Servlet only) threads:{}/iters:{}/total-matches:{} => {} ms",threads,iters,totalMatches,elapsed); - } - } - - @Stress("High CPU") - @Test - public void testServletPathMappings() - { - // Setup (new) PathMappings - - PathMappings<String> p = new PathMappings<>(); - - p.put(new ServletPathSpec("/abs/path"),"path"); - p.put(new ServletPathSpec("/abs/path/longer"),"longpath"); - p.put(new ServletPathSpec("/animal/bird/*"),"birds"); - p.put(new ServletPathSpec("/animal/fish/*"),"fishes"); - p.put(new ServletPathSpec("/animal/*"),"animals"); - p.put(new ServletPathSpec("*.tar.gz"),"tarball"); - p.put(new ServletPathSpec("*.gz"),"gzipped"); - p.put(new ServletPathSpec("/"),"default"); - - final CyclicBarrier barrier = new CyclicBarrier(threads + 1); - - for (int r = 0; r < runs; r++) - { - for (int t = 0; t < threads; t++) - { - PathMatchThread thread = new PathMatchThread(p,iters,barrier); - thread.start(); - } - await(barrier); - long begin = System.nanoTime(); - await(barrier); - long end = System.nanoTime(); - long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); - int totalMatches = threads * iters * LOOKUPS.length; - LOG.info("jetty-websocket/PathMappings (Servlet only) threads:{}/iters:{}/total-matches:{} => {} ms",threads,iters,totalMatches,elapsed); - - } - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java index 1479393f01..2ba15abe9d 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/PathMappingsTest.java @@ -20,7 +20,9 @@ package org.eclipse.jetty.websocket.jsr356.server.pathmap; import static org.hamcrest.Matchers.*; -import org.eclipse.jetty.websocket.jsr356.server.pathmap.PathMappings.MappedResource; +import org.eclipse.jetty.websocket.server.pathmap.PathMappings; +import org.eclipse.jetty.websocket.server.pathmap.PathMappings.MappedResource; +import org.eclipse.jetty.websocket.server.pathmap.ServletPathSpec; import org.junit.Assert; import org.junit.Test; @@ -73,49 +75,6 @@ public class PathMappingsTest } /** - * Test the match order rules imposed by the Servlet API. - * <p> - * <ul> - * <li>Exact match</li> - * <li>Longest prefix match</li> - * <li>Longest suffix match</li> - * <li>default</li> - * </ul> - */ - @Test - public void testServletMatchOrder() - { - PathMappings<String> p = new PathMappings<>(); - - p.put(new ServletPathSpec("/abs/path"),"path"); - p.put(new ServletPathSpec("/abs/path/longer"),"longpath"); - p.put(new ServletPathSpec("/animal/bird/*"),"birds"); - p.put(new ServletPathSpec("/animal/fish/*"),"fishes"); - p.put(new ServletPathSpec("/animal/*"),"animals"); - p.put(new ServletPathSpec("*.tar.gz"),"tarball"); - p.put(new ServletPathSpec("*.gz"),"gzipped"); - p.put(new ServletPathSpec("/"),"default"); - - for (MappedResource<String> res : p) - { - System.out.printf(" %s%n",res); - } - - assertMatch(p,"/abs/path","path"); - assertMatch(p,"/abs/path/longer","longpath"); - assertMatch(p,"/abs/path/foo","default"); - assertMatch(p,"/main.css","default"); - assertMatch(p,"/downloads/script.gz","gzipped"); - assertMatch(p,"/downloads/distribution.tar.gz","tarball"); - assertMatch(p,"/downloads/readme.txt","default"); - assertMatch(p,"/downloads/logs.tgz","default"); - assertMatch(p,"/animal/horse/mustang","animals"); - assertMatch(p,"/animal/bird/eagle/bald","birds"); - assertMatch(p,"/animal/fish/shark/hammerhead","fishes"); - assertMatch(p,"/animal/insect/ladybug","animals"); - } - - /** * Test the match order rules imposed by the WebSocket API (JSR-356) * <p> * <ul> diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/RegexPathSpecTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/RegexPathSpecTest.java deleted file mode 100644 index cdcc150676..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/RegexPathSpecTest.java +++ /dev/null @@ -1,113 +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.pathmap; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -import org.junit.Test; - -public class RegexPathSpecTest -{ - public static void assertMatches(PathSpec spec, String path) - { - String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path); - assertThat(msg,spec.matches(path),is(true)); - } - - public static void assertNotMatches(PathSpec spec, String path) - { - String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path); - assertThat(msg,spec.matches(path),is(false)); - } - - @Test - public void testExactSpec() - { - RegexPathSpec spec = new RegexPathSpec("^/a$"); - assertEquals("Spec.pathSpec","^/a$",spec.getPathSpec()); - assertEquals("Spec.pattern","^/a$",spec.getPattern().pattern()); - assertEquals("Spec.pathDepth",1,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.EXACT,spec.group); - - assertMatches(spec,"/a"); - - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/a/"); - } - - @Test - public void testMiddleSpec() - { - RegexPathSpec spec = new RegexPathSpec("^/rest/([^/]*)/list$"); - assertEquals("Spec.pathSpec","^/rest/([^/]*)/list$",spec.getPathSpec()); - assertEquals("Spec.pattern","^/rest/([^/]*)/list$",spec.getPattern().pattern()); - assertEquals("Spec.pathDepth",3,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.group); - - assertMatches(spec,"/rest/api/list"); - assertMatches(spec,"/rest/1.0/list"); - assertMatches(spec,"/rest/2.0/list"); - assertMatches(spec,"/rest/accounts/list"); - - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); - assertNotMatches(spec,"/rest/admin/delete"); - assertNotMatches(spec,"/rest/list"); - } - - @Test - public void testPrefixSpec() - { - RegexPathSpec spec = new RegexPathSpec("^/a/(.*)$"); - assertEquals("Spec.pathSpec","^/a/(.*)$",spec.getPathSpec()); - assertEquals("Spec.pattern","^/a/(.*)$",spec.getPattern().pattern()); - assertEquals("Spec.pathDepth",2,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.group); - - assertMatches(spec,"/a/"); - assertMatches(spec,"/a/b"); - assertMatches(spec,"/a/b/c/d/e"); - - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); - } - - @Test - public void testSuffixSpec() - { - RegexPathSpec spec = new RegexPathSpec("^(.*).do$"); - assertEquals("Spec.pathSpec","^(.*).do$",spec.getPathSpec()); - assertEquals("Spec.pattern","^(.*).do$",spec.getPattern().pattern()); - assertEquals("Spec.pathDepth",0,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.SUFFIX_GLOB,spec.group); - - assertMatches(spec,"/a.do"); - assertMatches(spec,"/a/b/c.do"); - assertMatches(spec,"/abcde.do"); - assertMatches(spec,"/abc/efg.do"); - - assertNotMatches(spec,"/a"); - assertNotMatches(spec,"/aa"); - assertNotMatches(spec,"/aa/bb"); - assertNotMatches(spec,"/aa/bb.do/more"); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/ServletPathSpecTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/ServletPathSpecTest.java deleted file mode 100644 index f1bd83a2fa..0000000000 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/ServletPathSpecTest.java +++ /dev/null @@ -1,186 +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.pathmap; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -import org.junit.Test; - -public class ServletPathSpecTest -{ - private void assertBadServletPathSpec(String pathSpec) - { - try - { - new ServletPathSpec(pathSpec); - fail("Expected IllegalArgumentException for a bad servlet pathspec on: " + pathSpec); - } - catch (IllegalArgumentException e) - { - // expected path - System.out.println(e); - } - } - - private void assertMatches(ServletPathSpec spec, String path) - { - String msg = String.format("Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path); - assertThat(msg,spec.matches(path),is(true)); - } - - private void assertNotMatches(ServletPathSpec spec, String path) - { - String msg = String.format("!Spec(\"%s\").matches(\"%s\")",spec.getPathSpec(),path); - assertThat(msg,spec.matches(path),is(false)); - } - - @Test - public void testBadServletPathSpecA() - { - assertBadServletPathSpec("foo"); - } - - @Test - public void testBadServletPathSpecB() - { - assertBadServletPathSpec("/foo/*.do"); - } - - @Test - public void testBadServletPathSpecC() - { - assertBadServletPathSpec("foo/*.do"); - } - - @Test - public void testBadServletPathSpecD() - { - assertBadServletPathSpec("foo/*.*do"); - } - - @Test - public void testBadServletPathSpecE() - { - assertBadServletPathSpec("*do"); - } - - @Test - public void testDefaultPathSpec() - { - ServletPathSpec spec = new ServletPathSpec("/"); - assertEquals("Spec.pathSpec","/",spec.getPathSpec()); - assertEquals("Spec.pathDepth",-1,spec.getPathDepth()); - } - - @Test - public void testEmptyPathSpec() - { - ServletPathSpec spec = new ServletPathSpec(""); - assertEquals("Spec.pathSpec","/",spec.getPathSpec()); - assertEquals("Spec.pathDepth",-1,spec.getPathDepth()); - } - - @Test - public void testExactPathSpec() - { - ServletPathSpec spec = new ServletPathSpec("/abs/path"); - assertEquals("Spec.pathSpec","/abs/path",spec.getPathSpec()); - assertEquals("Spec.pathDepth",2,spec.getPathDepth()); - - assertMatches(spec,"/abs/path"); - assertMatches(spec,"/abs/path/"); - - assertNotMatches(spec,"/abs/path/more"); - assertNotMatches(spec,"/foo"); - assertNotMatches(spec,"/foo/abs/path"); - assertNotMatches(spec,"/foo/abs/path/"); - } - - @Test - public void testGetPathInfo() - { - assertEquals("pathInfo exact",null,new ServletPathSpec("/Foo/bar").getPathInfo("/Foo/bar")); - assertEquals("pathInfo prefix","/bar",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/bar")); - assertEquals("pathInfo prefix","/*",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/*")); - assertEquals("pathInfo prefix","/",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/")); - assertEquals("pathInfo prefix",null,new ServletPathSpec("/Foo/*").getPathInfo("/Foo")); - assertEquals("pathInfo suffix",null,new ServletPathSpec("*.ext").getPathInfo("/Foo/bar.ext")); - assertEquals("pathInfo default",null,new ServletPathSpec("/").getPathInfo("/Foo/bar.ext")); - - assertEquals("pathInfo default","/xxx/zzz",new ServletPathSpec("/*").getPathInfo("/xxx/zzz")); - } - - @Test - public void testNullPathSpec() - { - ServletPathSpec spec = new ServletPathSpec(null); - assertEquals("Spec.pathSpec","/",spec.getPathSpec()); - assertEquals("Spec.pathDepth",-1,spec.getPathDepth()); - } - - @Test - public void testPathMatch() - { - assertEquals("pathMatch exact","/Foo/bar",new ServletPathSpec("/Foo/bar").getPathMatch("/Foo/bar")); - assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo/bar")); - assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo/")); - assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo")); - assertEquals("pathMatch suffix","/Foo/bar.ext",new ServletPathSpec("*.ext").getPathMatch("/Foo/bar.ext")); - assertEquals("pathMatch default","/Foo/bar.ext",new ServletPathSpec("/").getPathMatch("/Foo/bar.ext")); - - assertEquals("pathMatch default","",new ServletPathSpec("/*").getPathMatch("/xxx/zzz")); - } - - @Test - public void testPrefixPathSpec() - { - ServletPathSpec spec = new ServletPathSpec("/downloads/*"); - assertEquals("Spec.pathSpec","/downloads/*",spec.getPathSpec()); - assertEquals("Spec.pathDepth",2,spec.getPathDepth()); - - assertMatches(spec,"/downloads/logo.jpg"); - assertMatches(spec,"/downloads/distribution.tar.gz"); - assertMatches(spec,"/downloads/distribution.tgz"); - assertMatches(spec,"/downloads/distribution.zip"); - - assertMatches(spec,"/downloads"); - - assertEquals("Spec.pathInfo","/",spec.getPathInfo("/downloads/")); - assertEquals("Spec.pathInfo","/distribution.zip",spec.getPathInfo("/downloads/distribution.zip")); - assertEquals("Spec.pathInfo","/dist/9.0/distribution.tar.gz",spec.getPathInfo("/downloads/dist/9.0/distribution.tar.gz")); - } - - @Test - public void testSuffixPathSpec() - { - ServletPathSpec spec = new ServletPathSpec("*.gz"); - assertEquals("Spec.pathSpec","*.gz",spec.getPathSpec()); - assertEquals("Spec.pathDepth",0,spec.getPathDepth()); - - assertMatches(spec,"/downloads/distribution.tar.gz"); - assertMatches(spec,"/downloads/jetty.log.gz"); - - assertNotMatches(spec,"/downloads/distribution.zip"); - assertNotMatches(spec,"/downloads/distribution.tgz"); - assertNotMatches(spec,"/abs/path"); - - assertEquals("Spec.pathInfo",null,spec.getPathInfo("/downloads/distribution.tar.gz")); - } -} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java index ef84852009..d85d0bb7af 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/pathmap/WebSocketPathSpecTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.*; import java.util.Map; +import org.eclipse.jetty.websocket.server.pathmap.PathSpecGroup; import org.junit.Test; /** @@ -60,7 +61,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/",spec.getPathSpec()); assertEquals("Spec.pattern","^/$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",1,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.EXACT,spec.group); + assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup()); assertEquals("Spec.variableCount",0,spec.getVariableCount()); assertEquals("Spec.variable.length",0,spec.getVariables().length); @@ -73,7 +74,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/a",spec.getPathSpec()); assertEquals("Spec.pattern","^/a$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",1,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.EXACT,spec.group); + assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup()); assertEquals("Spec.variableCount",0,spec.getVariableCount()); assertEquals("Spec.variable.length",0,spec.getVariables().length); @@ -86,7 +87,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/a/b",spec.getPathSpec()); assertEquals("Spec.pattern","^/a/b$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",2,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.EXACT,spec.group); + assertEquals("Spec.group",PathSpecGroup.EXACT,spec.getGroup()); assertEquals("Spec.variableCount",0,spec.getVariableCount()); assertEquals("Spec.variable.length",0,spec.getVariables().length); @@ -105,7 +106,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/a/{var}/c",spec.getPathSpec()); assertEquals("Spec.pattern","^/a/([^/]+)/c$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",3,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.getGroup()); assertDetectedVars(spec,"var"); @@ -129,7 +130,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/a/{foo}",spec.getPathSpec()); assertEquals("Spec.pattern","^/a/([^/]+)$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",2,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.getGroup()); assertDetectedVars(spec,"foo"); @@ -150,7 +151,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/{var}/b/c",spec.getPathSpec()); assertEquals("Spec.pattern","^/([^/]+)/b/c$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",3,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.SUFFIX_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.SUFFIX_GLOB,spec.getGroup()); assertDetectedVars(spec,"var"); @@ -174,7 +175,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/a/{var1}/c/{var2}/e",spec.getPathSpec()); assertEquals("Spec.pattern","^/a/([^/]+)/c/([^/]+)/e$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",5,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.getGroup()); assertDetectedVars(spec,"var1","var2"); @@ -197,7 +198,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/{var1}/b/{var2}/{var3}",spec.getPathSpec()); assertEquals("Spec.pattern","^/([^/]+)/b/([^/]+)/([^/]+)$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",4,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.MIDDLE_GLOB,spec.getGroup()); assertDetectedVars(spec,"var1","var2","var3"); @@ -221,7 +222,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/a/{var1}/{var2}",spec.getPathSpec()); assertEquals("Spec.pattern","^/a/([^/]+)/([^/]+)$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",3,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.getGroup()); assertDetectedVars(spec,"var1","var2"); @@ -244,7 +245,7 @@ public class WebSocketPathSpecTest assertEquals("Spec.pathSpec","/{var1}",spec.getPathSpec()); assertEquals("Spec.pattern","^/([^/]+)$",spec.getPattern().pattern()); assertEquals("Spec.pathDepth",1,spec.getPathDepth()); - assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.group); + assertEquals("Spec.group",PathSpecGroup.PREFIX_GLOB,spec.getGroup()); assertDetectedVars(spec,"var1"); diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpoint.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpoint.java new file mode 100644 index 0000000000..761fc0cde4 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpoint.java @@ -0,0 +1,46 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server.samples.echo; + +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.MessageHandler; +import javax.websocket.Session; + +/** + * Example of websocket endpoint based on extending {@link Endpoint} + */ +public class BasicEchoEndpoint extends Endpoint implements MessageHandler.Whole<String> +{ + private Session session; + + @Override + public void onMessage(String msg) + { + // reply with echo + session.getAsyncRemote().sendText(msg); + } + + @Override + public void onOpen(Session session, EndpointConfig config) + { + this.session = session; + this.session.addMessageHandler(this); + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java new file mode 100644 index 0000000000..d64057aab8 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointConfigContextListener.java @@ -0,0 +1,56 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server.samples.echo; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.websocket.ContainerProvider; +import javax.websocket.DeploymentException; +import javax.websocket.Endpoint; +import javax.websocket.server.ServerContainer; +import javax.websocket.server.ServerEndpointConfig; + +/** + * Example of adding a server WebSocket (extending {@link Endpoint}) programmatically via config + */ +public class BasicEchoEndpointConfigContextListener implements ServletContextListener +{ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + /* do nothing */ + } + + @Override + public void contextInitialized(ServletContextEvent sce) + { + ServerContainer container = (ServerContainer)ContainerProvider.getWebSocketContainer(); + // Build up a configuration with a specific path + String path = "/echo"; + ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(BasicEchoEndpoint.class,path); + try + { + container.addEndpoint(builder.build()); + } + catch (DeploymentException e) + { + throw new RuntimeException("Unable to add endpoint via config file",e); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java new file mode 100644 index 0000000000..035e386be9 --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoEndpointContextListener.java @@ -0,0 +1,55 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server.samples.echo; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.websocket.ContainerProvider; +import javax.websocket.DeploymentException; +import javax.websocket.Endpoint; +import javax.websocket.server.ServerContainer; + +/** + * Example of adding a server WebSocket (extending {@link Endpoint}) programmatically directly. + * <p> + * NOTE: this shouldn't work as the endpoint has no path associated with it. + */ +public class BasicEchoEndpointContextListener implements ServletContextListener +{ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + /* do nothing */ + } + + @Override + public void contextInitialized(ServletContextEvent sce) + { + ServerContainer container = (ServerContainer)ContainerProvider.getWebSocketContainer(); + try + { + // Should fail as there is no path associated with this endpoint + container.addEndpoint(BasicEchoEndpoint.class); + } + catch (DeploymentException e) + { + throw new RuntimeException("Unable to add endpoint directly",e); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/BasicEchoSocket.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocket.java index fa49975cc4..49a7e2e504 100644 --- a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/BasicEchoSocket.java +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocket.java @@ -16,12 +16,15 @@ // ======================================================================== // -package org.eclipse.jetty.websocket.jsr356.server.samples; +package org.eclipse.jetty.websocket.jsr356.server.samples.echo; import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; +/** + * Annotated echo socket + */ @ServerEndpoint("/echo") public class BasicEchoSocket { diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java new file mode 100644 index 0000000000..401dd12f6e --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketConfigContextListener.java @@ -0,0 +1,56 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server.samples.echo; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.websocket.ContainerProvider; +import javax.websocket.DeploymentException; +import javax.websocket.server.ServerContainer; +import javax.websocket.server.ServerEndpointConfig; + +/** + * Example of adding a server socket (annotated) programmatically via config + */ +public class BasicEchoSocketConfigContextListener implements ServletContextListener +{ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + /* do nothing */ + } + + @Override + public void contextInitialized(ServletContextEvent sce) + { + ServerContainer container = (ServerContainer)ContainerProvider.getWebSocketContainer(); + // Build up a configuration with a specific path + // Intentionally using alternate path in config (which differs from @ServerEndpoint declaration) + String path = "/echo-alt"; + ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(BasicEchoSocket.class,path); + try + { + container.addEndpoint(builder.build()); + } + catch (DeploymentException e) + { + throw new RuntimeException("Unable to add endpoint via config file",e); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketContextListener.java b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketContextListener.java new file mode 100644 index 0000000000..9e720d016c --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/BasicEchoSocketContextListener.java @@ -0,0 +1,51 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.websocket.jsr356.server.samples.echo; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.websocket.ContainerProvider; +import javax.websocket.DeploymentException; +import javax.websocket.server.ServerContainer; + +/** + * Example of adding a server socket (annotated) programmatically directly with no config + */ +public class BasicEchoSocketContextListener implements ServletContextListener +{ + @Override + public void contextDestroyed(ServletContextEvent sce) + { + /* do nothing */ + } + + @Override + public void contextInitialized(ServletContextEvent sce) + { + ServerContainer container = (ServerContainer)ContainerProvider.getWebSocketContainer(); + try + { + container.addEndpoint(BasicEchoSocket.class); + } + catch (DeploymentException e) + { + throw new RuntimeException("Unable to add endpoint directly",e); + } + } +} diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/resources/basic-echo-endpoint-config-web.xml b/jetty-websocket/javax-websocket-server-impl/src/test/resources/basic-echo-endpoint-config-web.xml new file mode 100644 index 0000000000..afd9cef68d --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/resources/basic-echo-endpoint-config-web.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<web-app + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="http://java.sun.com/xml/ns/javaee" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + metadata-complete="false" + version="3.0"> + + <listener> + <listener-class>org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoEndpointConfigContextListener</listener-class> + </listener> +</web-app>
\ No newline at end of file diff --git a/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties b/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties new file mode 100644 index 0000000000..95a7e3fbed --- /dev/null +++ b/jetty-websocket/javax-websocket-server-impl/src/test/resources/jetty-logging.properties @@ -0,0 +1,7 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +org.eclipse.jetty.LEVEL=WARN + +org.eclipse.jetty.websocket.LEVEL=DEBUG +# org.eclipse.jetty.websocket.LEVEL=WARN +# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG + |