Author: markt Date: Fri Mar 29 21:34:18 2013 New Revision: 1462653 URL: http://svn.apache.org/r1462653 Log: Switch to a Filter based rather than Servlet based implementation and fully implement the mapping rules for WebSocket requests.
Added: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsFilter.java - copied, changed from r1461327, tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java tomcat/trunk/java/org/apache/tomcat/websocket/server/WsMappingResult.java (with props) Removed: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java Modified: tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java tomcat/trunk/java/org/apache/tomcat/websocket/server/UriTemplate.java tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java tomcat/trunk/test/org/apache/tomcat/websocket/TestWsRemoteEndpoint.java tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java tomcat/trunk/test/org/apache/tomcat/websocket/TesterEchoServer.java tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestEncodingDecoding.java tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java tomcat/trunk/test/org/apache/tomcat/websocket/server/TestUriTemplate.java Modified: tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/server/Constants.java Fri Mar 29 21:34:18 2013 @@ -23,7 +23,6 @@ public class Constants { protected static final String PACKAGE_NAME = Constants.class.getPackage().getName(); - protected static final String SERVLET_NAME = WsServlet.class.getName(); public static final String BINARY_BUFFER_SIZE_SERVLET_CONTEXT_INIT_PARAM = "org.apache.tomcat.websocket.binaryBufferSize"; Modified: tomcat/trunk/java/org/apache/tomcat/websocket/server/UriTemplate.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/UriTemplate.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/server/UriTemplate.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/server/UriTemplate.java Fri Mar 29 21:34:18 2013 @@ -17,14 +17,10 @@ package org.apache.tomcat.websocket.server; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.tomcat.util.res.StringManager; /** * Extracts path parameters from URIs used to create web socket connections @@ -32,68 +28,119 @@ import org.apache.tomcat.util.res.String */ public class UriTemplate { - private static final StringManager sm = - StringManager.getManager(Constants.PACKAGE_NAME); + private final String normalized; + private final List<Segment> segments = new ArrayList<>(); + private final boolean hasParameters; + + + public UriTemplate(String path) { + StringBuilder normalized = new StringBuilder(path.length()); + + String[] segments = path.split("/"); + int paramCount = 0; + int segmentCount = 0; + + for (int i = 0; i < segments.length; i++) { + String segment = segments[i]; + if (segment.length() == 0) { + continue; + } + normalized.append('/'); + int index = -1; + if (segment.startsWith("{") && segment.endsWith("}")) { + index = segmentCount; + segment = segment.substring(1, segment.length() - 1); + normalized.append('{'); + normalized.append(paramCount++); + normalized.append('}'); + } else { + if (segment.contains("{") || segment.contains("}")) { + // TODO i18n + throw new IllegalArgumentException(); + } + normalized.append(segment); + } + this.segments.add(new Segment(index, segment)); + segmentCount++; + } - private final String template; - private final Pattern pattern; - private final List<String> names = new ArrayList<>(); - - - public UriTemplate(String template) { - this.template = template; - // +10 is just a guess at this point - StringBuilder pattern = new StringBuilder(template.length() + 10); - int pos = 0; - int end = 0; - int start = template.indexOf('{'); - while (start > -1) { - end = template.indexOf('}', start); - pattern.append('('); - pattern.append(Pattern.quote(template.substring(pos, start))); - pattern.append(")([^/]*)"); - names.add(template.substring(start + 1, end)); - pos = end + 1; - start = template.indexOf('{', pos); - } - // No more matches, append current position to end - if (pos < template.length()) { - pattern.append('('); - pattern.append(template.substring(pos)); - pattern.append(")?"); - } - this.pattern = Pattern.compile(pattern.toString()); + this.normalized = normalized.toString(); + this.hasParameters = paramCount > 0; } - public boolean contains(String name) { - return names.contains(name); - } - + public Map<String,String> match(UriTemplate candidate) { - /** - * Extract the path parameters from the provided pathInfo based on the - * template with which this UriTemplate was constructed. - * - * @param pathInfo The pathInfo from which the path parameters are to be - * extracted - * @return A map of parameter names to values - */ - public Map<String,String> match(String pathInfo) { Map<String,String> result = new HashMap<>(); - Matcher m = pattern.matcher(pathInfo); - if (!m.matches()) { - throw new IllegalArgumentException(sm.getString( - "uriTemplate.noMatch", template, pattern, pathInfo)); - } - int group = 2; - for (String name : names) { - String value = m.group(group); - if (value != null && value.length() > 0) { - result.put(name, value); + + // Should not happen but for safety + if (candidate.getSegmentCount() != getSegmentCount()) { + return null; + } + + Iterator<Segment> candidateSegments = + candidate.getSegments().iterator(); + Iterator<Segment> targetSegments = segments.iterator(); + + while (candidateSegments.hasNext()) { + Segment candidateSegment = candidateSegments.next(); + Segment targetSegment = targetSegments.next(); + + if (targetSegment.getParameterIndex() == -1) { + // Not a parameter - values must match + if (!targetSegment.getValue().equals( + candidateSegment.getValue())) { + // Not a match. Stop here + return null; + } + } else { + // Parameter + result.put(targetSegment.getValue(), + candidateSegment.getValue()); } - group += 2; } - return Collections.unmodifiableMap(result); + + return result; + } + + + public boolean hasParameters() { + return hasParameters; + } + + + public int getSegmentCount() { + return segments.size(); + } + + + public String getNormalizedPath() { + return normalized; + } + + + private List<Segment> getSegments() { + return segments; + } + + + private static class Segment { + private final int parameterIndex; + private final String value; + + public Segment(int parameterIndex, String value) { + this.parameterIndex = parameterIndex; + this.value = value; + } + + + public int getParameterIndex() { + return parameterIndex; + } + + + public String getValue() { + return value; + } } } Copied: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsFilter.java (from r1461327, tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java) URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsFilter.java?p2=tomcat/trunk/java/org/apache/tomcat/websocket/server/WsFilter.java&p1=tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java&r1=1461327&r2=1462653&rev=1462653&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServlet.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsFilter.java Fri Mar 29 21:34:18 2013 @@ -25,13 +25,16 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.websocket.Endpoint; @@ -47,29 +50,49 @@ import org.apache.tomcat.websocket.pojo. /** * Handles the initial HTTP connection for WebSocket connections. */ -public class WsServlet extends HttpServlet { +public class WsFilter implements Filter { - private static final long serialVersionUID = 1L; private static final Charset ISO_8859_1; static { ISO_8859_1 = Charset.forName("ISO-8859-1"); } - private static final byte[] WS_ACCEPT = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(ISO_8859_1); - private final Queue<MessageDigest> sha1Helpers = new ConcurrentLinkedQueue<>(); + private static final byte[] WS_ACCEPT = + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".getBytes(ISO_8859_1); + private final Queue<MessageDigest> sha1Helpers = + new ConcurrentLinkedQueue<>(); @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - // Information required to send the server handshake message + public void init(FilterConfig filterConfig) throws ServletException { + // NO-OP + } + + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + + // This filter only needs to handle WebSocket upgrade requests + if (!(request instanceof HttpServletRequest) || + !(response instanceof HttpServletResponse) || + !headerContainsToken((HttpServletRequest) request, + Constants.UPGRADE_HEADER_NAME, + Constants.UPGRADE_HEADER_VALUE)) { + // Note an HTTP request that includes a valid upgrade request to + // web socket + chain.doFilter(request, response); + return; + } + + // HTTP request with an upgrade header for WebSocket present + // Validate the rest of the headers and reject the request if that + // validation fails + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + String key; String subProtocol = null; List<Extension> extensions = Collections.emptyList(); - if (!headerContainsToken(req, Constants.UPGRADE_HEADER_NAME, - Constants.UPGRADE_HEADER_VALUE)) { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST); - return; - } if (!headerContainsToken(req, Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE)) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST); @@ -87,12 +110,20 @@ public class WsServlet extends HttpServl resp.sendError(HttpServletResponse.SC_BAD_REQUEST); return; } + // Need an Endpoint instance to progress this further WsServerContainer sc = WsServerContainer.getServerContainer(); - Map<String,String> pathParameters = sc.getPathParameters( - req.getServletPath(), req.getPathInfo()); - ServerEndpointConfig sec = sc.getServerEndpointConfiguration( - req.getServletPath(), pathParameters); + String path; + String pathInfo = req.getPathInfo(); + if (pathInfo == null) { + path = req.getServletPath(); + } else { + path = req.getServletPath() + pathInfo; + } + WsMappingResult mappingResult = sc.findMapping(path); + + ServerEndpointConfig sec = mappingResult.getConfig(); + // Origin check String origin = req.getHeader("Origin"); if (!sec.getConfigurator().checkOrigin(origin)) { @@ -136,7 +167,7 @@ public class WsServlet extends HttpServl Class<?> clazz = sec.getEndpointClass(); if (Endpoint.class.isAssignableFrom(clazz)) { ep = (Endpoint) sec.getConfigurator().getEndpointInstance( - sec.getEndpointClass()); + clazz); } else { ep = new PojoEndpointServer(); } @@ -159,8 +190,15 @@ public class WsServlet extends HttpServl WsHttpUpgradeHandler wsHandler = req.upgrade(WsHttpUpgradeHandler.class); - wsHandler.preInit(ep, sec, sc, wsRequest, subProtocol, pathParameters, - req.isSecure()); + wsHandler.preInit(ep, sec, sc, wsRequest, subProtocol, + mappingResult.getPathParams(), req.isSecure()); + + } + + + @Override + public void destroy() { + // NO-OP } Added: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsMappingResult.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsMappingResult.java?rev=1462653&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/server/WsMappingResult.java (added) +++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsMappingResult.java Fri Mar 29 21:34:18 2013 @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.websocket.server; + +import java.util.Map; + +import javax.websocket.server.ServerEndpointConfig; + +class WsMappingResult { + + private final ServerEndpointConfig config; + private final Map<String,String> pathParams; + + + WsMappingResult(ServerEndpointConfig config, + Map<String,String> pathParams) { + this.config = config; + this.pathParams = pathParams; + } + + + ServerEndpointConfig getConfig() { + return config; + } + + + Map<String,String> getPathParams() { + return pathParams; + } +} Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsMappingResult.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java Fri Mar 29 21:34:18 2013 @@ -18,20 +18,21 @@ package org.apache.tomcat.websocket.serv import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentHashMap; +import javax.servlet.FilterRegistration; import javax.servlet.ServletContext; -import javax.servlet.ServletRegistration; import javax.websocket.DeploymentException; import javax.websocket.server.ServerContainer; import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpointConfig; import javax.websocket.server.ServerEndpointConfig.Configurator; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; import org.apache.tomcat.websocket.WsSession; import org.apache.tomcat.websocket.WsWebSocketContainer; @@ -58,7 +59,6 @@ public class WsServerContainer extends W private static final Object classLoaderContainerMapLock = new Object(); private static final StringManager sm = StringManager.getManager(Constants.PACKAGE_NAME); - private final Log log = LogFactory.getLog(WsServerContainer.class); public static WsServerContainer getServerContainer() { @@ -77,13 +77,10 @@ public class WsServerContainer extends W private final WsWriteTimeout wsWriteTimeout = new WsWriteTimeout(); private volatile ServletContext servletContext = null; - private final Map<String,ServerEndpointConfig> configMap = - new ConcurrentHashMap<>(); - private final Map<String,UriTemplate> templateMap = - new ConcurrentHashMap<>(); - private final Map<String,Class<?>> pojoMap = new ConcurrentHashMap<>(); - private final Map<Class<?>,PojoMethodMapping> pojoMethodMap = - new ConcurrentHashMap<>(); + private final Map<String,ServerEndpointConfig> configExactMatchMap = + new HashMap<>(); + private final Map<Integer,SortedSet<TemplatePathMatch>> + configTemplateMatchMap = new HashMap<>(); private WsServerContainer() { @@ -111,6 +108,10 @@ public class WsServerContainer extends W if (value != null) { setDefaultMaxTextMessageBufferSize(Integer.parseInt(value)); } + + FilterRegistration fr = servletContext.addFilter( + WsFilter.class.getName(), WsFilter.class); + fr.addMappingForUrlPatterns(null, false, "/*"); } @@ -130,23 +131,21 @@ public class WsServerContainer extends W sm.getString("serverContainer.servletContextMissing")); } String path = sec.getPath(); - String servletPath = getServletPath(path); - if (log.isDebugEnabled()) { - log.debug(sm.getString("serverContainer.endpointDeploy", - sec.getEndpointClass(), path, - servletContext.getContextPath())); - } - - // Remove the trailing /* before adding it to the map - String mapPath = servletPath.substring(0, servletPath.length() - 2); - if (path.length() > servletPath.length()) { - templateMap.put(mapPath, - new UriTemplate(path.substring(mapPath.length()))); + UriTemplate uriTemplate = new UriTemplate(path); + if (uriTemplate.hasParameters()) { + Integer key = Integer.valueOf(uriTemplate.getSegmentCount()); + SortedSet<TemplatePathMatch> templateMatches = + configTemplateMatchMap.get(key); + if (templateMatches == null) { + templateMatches = new TreeSet<>(); + configTemplateMatchMap.put(key, templateMatches); + } + templateMatches.add(new TemplatePathMatch(sec, uriTemplate)); + } else { + // Exact match + configExactMatchMap.put(path, sec); } - - configMap.put(mapPath, sec); - addWsServletMapping(servletPath); } @@ -166,94 +165,97 @@ public class WsServerContainer extends W sm.getString("serverContainer.missingAnnotation", pojo.getName())); } - String wsPath = annotation.value(); - - if (log.isDebugEnabled()) { - log.debug(sm.getString("serverContainer.pojoDeploy", - pojo.getName(), wsPath, servletContext.getContextPath())); - } + String path = annotation.value(); - String servletPath = getServletPath(wsPath); - // Remove the trailing /* before adding it to the map - String mapPath = servletPath.substring(0, servletPath.length() - 2); + // Uri Template + UriTemplate uriTemplate = new UriTemplate(path); - if (wsPath.length() > servletPath.length()) { - templateMap.put(mapPath, - new UriTemplate(wsPath.substring(mapPath.length()))); + // Method mapping + PojoMethodMapping methodMapping = new PojoMethodMapping(pojo, + annotation.decoders(), path); + + // ServerEndpointConfig + ServerEndpointConfig sec; + Class<? extends Configurator> configuratorClazz = + annotation.configurator(); + Configurator configurator = null; + if (!configuratorClazz.equals(Configurator.class)) { + try { + configurator = annotation.configurator().newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new IllegalStateException(sm.getString( + "serverContainer.configuratorFail", + annotation.configurator().getName(), + pojo.getClass().getName()), e); + } } - - pojoMap.put(mapPath, pojo); - pojoMethodMap.put(pojo, - new PojoMethodMapping(pojo, annotation.decoders(), wsPath)); - addWsServletMapping(servletPath); - } - - - private void addWsServletMapping(String servletPath) { - ServletRegistration sr = - servletContext.getServletRegistration(Constants.SERVLET_NAME); - if (sr == null) { - sr = servletContext.addServlet(Constants.SERVLET_NAME, - WsServlet.class); + sec = ServerEndpointConfig.Builder.create(pojo, path). + decoders(Arrays.asList(annotation.decoders())). + encoders(Arrays.asList(annotation.encoders())). + configurator(configurator). + build(); + sec.getUserProperties().put( + PojoEndpointServer.POJO_METHOD_MAPPING_KEY, + methodMapping); + + + if (uriTemplate.hasParameters()) { + Integer key = Integer.valueOf(uriTemplate.getSegmentCount()); + SortedSet<TemplatePathMatch> templateMatches = + configTemplateMatchMap.get(key); + if (templateMatches == null) { + templateMatches = + new TreeSet<>(new TemplatePathMatchComparator()); + configTemplateMatchMap.put(key, templateMatches); + } + templateMatches.add(new TemplatePathMatch(sec, uriTemplate)); + } else { + // Exact match + configExactMatchMap.put(path, sec); } - sr.addMapping(servletPath); } - public ServerEndpointConfig getServerEndpointConfiguration( - String servletPath, Map<String,String> pathParameters) { - ServerEndpointConfig sec = configMap.get(servletPath); + public WsMappingResult findMapping(String path) { + + // Check an exact match. Simple case as there are no templates. + ServerEndpointConfig sec = configExactMatchMap.get(path); if (sec != null) { - return sec; + return new WsMappingResult(sec, Collections.EMPTY_MAP); } - Class<?> pojo = pojoMap.get(servletPath); - if (pojo != null) { - ServerEndpoint annotation = - pojo.getAnnotation(ServerEndpoint.class); - PojoMethodMapping methodMapping = pojoMethodMap.get(pojo); - if (methodMapping != null) { - Class<? extends Configurator> configuratorClazz = - annotation.configurator(); - Configurator configurator = null; - if (!configuratorClazz.equals(Configurator.class)) { - try { - configurator = annotation.configurator().newInstance(); - } catch (InstantiationException | - IllegalAccessException e) { - throw new IllegalStateException(sm.getString( - "serverContainer.configuratorFail", - annotation.configurator().getName(), - pojo.getClass().getName()), e); - } - } - sec = ServerEndpointConfig.Builder.create( - pojo, methodMapping.getWsPath()). - decoders(Arrays.asList(annotation.decoders())). - encoders(Arrays.asList(annotation.encoders())). - configurator(configurator). - build(); - sec.getUserProperties().put( - PojoEndpointServer.POJO_PATH_PARAM_KEY, - pathParameters); - sec.getUserProperties().put( - PojoEndpointServer.POJO_METHOD_MAPPING_KEY, - methodMapping); - return sec; + + // No exact match. Need to look for template matches. + UriTemplate pathUriTemplate = new UriTemplate(path); + + // Number of segments has to match + Integer key = Integer.valueOf(pathUriTemplate.getSegmentCount()); + SortedSet<TemplatePathMatch> templateMatches = + configTemplateMatchMap.get(key); + + // List is in alphabetical order of normalised templates. + // Correct match is the first one that matches. + Map<String,String> pathParams = null; + for (TemplatePathMatch templateMatch : templateMatches) { + pathParams = templateMatch.getUriTemplate().match(pathUriTemplate); + if (pathParams != null) { + sec = templateMatch.getConfig(); + break; } } - throw new IllegalStateException(sm.getString( - "serverContainer.missingEndpoint", servletPath)); - } + if (sec == null) { + // No match + return null; + } - public Map<String,String> getPathParameters(String servletPath, - String pathInfo) { - UriTemplate template = templateMap.get(servletPath); - if (template == null) { - return Collections.EMPTY_MAP; - } else { - return template.match(pathInfo); + if (!PojoEndpointServer.class.isAssignableFrom(sec.getEndpointClass())) { + // Need to make path params available to POJO + sec.getUserProperties().put( + PojoEndpointServer.POJO_PATH_PARAM_KEY, + pathParams); } + + return new WsMappingResult(sec, pathParams); } @@ -308,4 +310,37 @@ public class WsServerContainer extends W } } } + + + private static class TemplatePathMatch { + private final ServerEndpointConfig config; + private final UriTemplate uriTemplate; + + public TemplatePathMatch(ServerEndpointConfig config, + UriTemplate uriTemplate) { + this.config = config; + this.uriTemplate = uriTemplate; + } + + + public ServerEndpointConfig getConfig() { + return config; + } + + + public UriTemplate getUriTemplate() { + return uriTemplate; + } + } + + + private static class TemplatePathMatchComparator + implements Comparator<TemplatePathMatch> { + + @Override + public int compare(TemplatePathMatch tpm1, TemplatePathMatch tpm2) { + return tpm1.getUriTemplate().getNormalizedPath().compareTo( + tpm2.getUriTemplate().getNormalizedPath()); + } + } } Modified: tomcat/trunk/test/org/apache/tomcat/websocket/TestWsRemoteEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TestWsRemoteEndpoint.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/TestWsRemoteEndpoint.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/TestWsRemoteEndpoint.java Fri Mar 29 21:34:18 2013 @@ -32,6 +32,7 @@ import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; import org.apache.tomcat.websocket.TesterSingleMessageClient.AsyncHandler; @@ -69,6 +70,8 @@ public class TestWsRemoteEndpoint extend Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); Modified: tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java Fri Mar 29 21:34:18 2013 @@ -43,6 +43,7 @@ import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; import org.apache.coyote.http11.Http11Protocol; @@ -79,12 +80,15 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); tomcat.start(); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); - Session wsSession = wsContainer.connectToServer(TesterProgrammaticEndpoint.class, + Session wsSession = wsContainer.connectToServer( + TesterProgrammaticEndpoint.class, ClientEndpointConfig.Builder.create().build(), new URI("ws://localhost:" + getPort() + TesterEchoServer.Config.PATH_ASYNC)); @@ -196,6 +200,8 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); @@ -282,6 +288,8 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(BlockingConfig.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); @@ -368,6 +376,8 @@ public class TestWsWebSocketContainer ex tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(WsListener.class.getName()); ctx.addApplicationListener(ConstantTxConfig.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); @@ -544,6 +554,8 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); tomcat.start(); @@ -586,6 +598,8 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); tomcat.start(); @@ -638,6 +652,8 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); tomcat.start(); @@ -720,6 +736,8 @@ public class TestWsWebSocketContainer ex Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); TesterSupport.initSsl(tomcat); Modified: tomcat/trunk/test/org/apache/tomcat/websocket/TesterEchoServer.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/TesterEchoServer.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/TesterEchoServer.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/TesterEchoServer.java Fri Mar 29 21:34:18 2013 @@ -39,7 +39,6 @@ public class TesterEchoServer { public void contextInitialized(ServletContextEvent sce) { super.contextInitialized(sce); WsServerContainer sc = WsServerContainer.getServerContainer(); - sc.setServletContext(sce.getServletContext()); try { sc.addEndpoint(Async.class); sc.addEndpoint(Basic.class); Modified: tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestEncodingDecoding.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestEncodingDecoding.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestEncodingDecoding.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestEncodingDecoding.java Fri Mar 29 21:34:18 2013 @@ -36,6 +36,7 @@ import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; import org.apache.tomcat.websocket.pojo.Util.ServerConfigListener; @@ -58,6 +59,8 @@ public class TestEncodingDecoding extend Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(ServerConfigListener.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); Modified: tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoEndpointBase.java Fri Mar 29 21:34:18 2013 @@ -31,6 +31,7 @@ import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; import org.apache.tomcat.websocket.pojo.Util.ServerConfigListener; @@ -51,6 +52,8 @@ public class TestPojoEndpointBase extend Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(ServerConfigListener.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); Modified: tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java Fri Mar 29 21:34:18 2013 @@ -33,6 +33,7 @@ import org.junit.Assert; import org.junit.Test; import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; import org.apache.tomcat.websocket.pojo.Util.ServerConfigListener; @@ -58,6 +59,8 @@ public class TestPojoMethodMapping exten Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); ctx.addApplicationListener(ServerConfigListener.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); WebSocketContainer wsContainer = ContainerProvider.getWebSocketContainer(); Modified: tomcat/trunk/test/org/apache/tomcat/websocket/server/TestUriTemplate.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/websocket/server/TestUriTemplate.java?rev=1462653&r1=1462652&r2=1462653&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/websocket/server/TestUriTemplate.java (original) +++ tomcat/trunk/test/org/apache/tomcat/websocket/server/TestUriTemplate.java Fri Mar 29 21:34:18 2013 @@ -26,7 +26,7 @@ public class TestUriTemplate { @Test public void testBasic() throws Exception { UriTemplate t = new UriTemplate("/{a}/{b}"); - Map<String,String> result = t.match("/foo/bar"); + Map<String,String> result = t.match(new UriTemplate("/foo/bar")); Assert.assertEquals(2, result.size()); Assert.assertTrue(result.containsKey("a")); @@ -36,62 +36,53 @@ public class TestUriTemplate { } - @Test(expected=java.lang.IllegalArgumentException.class) + @Test public void testOneOfTwo() throws Exception { UriTemplate t = new UriTemplate("/{a}/{b}"); - t.match("/foo"); + Map<String,String> result = t.match(new UriTemplate("/foo")); + Assert.assertNull(result); } - @Test + @Test(expected=java.lang.IllegalArgumentException.class) public void testBasicPrefix() throws Exception { + @SuppressWarnings("unused") UriTemplate t = new UriTemplate("/x{a}/y{b}"); - Map<String,String> result = t.match("/xfoo/ybar"); - - Assert.assertEquals(2, result.size()); - Assert.assertTrue(result.containsKey("a")); - Assert.assertTrue(result.containsKey("b")); - Assert.assertEquals("foo", result.get("a")); - Assert.assertEquals("bar", result.get("b")); } @Test(expected=java.lang.IllegalArgumentException.class) public void testPrefixOneOfTwo() throws Exception { UriTemplate t = new UriTemplate("/x{a}/y{b}"); - t.match("/xfoo"); + t.match(new UriTemplate("/xfoo")); } @Test(expected=java.lang.IllegalArgumentException.class) public void testPrefixTwoOfTwo() throws Exception { UriTemplate t = new UriTemplate("/x{a}/y{b}"); - t.match("/ybar"); + t.match(new UriTemplate("/ybar")); } @Test(expected=java.lang.IllegalArgumentException.class) public void testQuote1() throws Exception { UriTemplate t = new UriTemplate("/.{a}"); - t.match("/yfoo"); + t.match(new UriTemplate("/yfoo")); } - @Test + @Test(expected=java.lang.IllegalArgumentException.class) public void testQuote2() throws Exception { + @SuppressWarnings("unused") UriTemplate t = new UriTemplate("/.{a}"); - Map<String,String> result = t.match("/.foo"); - - Assert.assertEquals(1, result.size()); - Assert.assertTrue(result.containsKey("a")); - Assert.assertEquals("foo", result.get("a")); } @Test public void testNoParams() throws Exception { UriTemplate t = new UriTemplate("/foo/bar"); - Map<String,String> result = t.match("/foo/bar"); + Map<String,String> result = t.match(new UriTemplate("/foo/bar")); Assert.assertEquals(0, result.size()); } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org