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: [email protected]
For additional commands, e-mail: [email protected]