Author: sergeyb
Date: Wed Dec 3 10:04:20 2008
New Revision: 722988
URL: http://svn.apache.org/viewvc?rev=722988&view=rev
Log:
JAXRS : support for arbitrary regular expressions
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfoComparator.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfoComparator.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfoComparator.java?rev=722988&r1=722987&r2=722988&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfoComparator.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/OperationResourceInfoComparator.java
Wed Dec 3 10:04:20 2008
@@ -48,6 +48,12 @@
return g1 < g2 ? 1 : -1;
}
+ int gCustom1 =
e1.getURITemplate().getNumberOfGroupsWithCustomExpression();
+ int gCustom2 =
e2.getURITemplate().getNumberOfGroupsWithCustomExpression();
+ if (gCustom1 != gCustom2) {
+ // descending order
+ return gCustom1 < gCustom2 ? 1 : -1;
+ }
int result = JAXRSUtils.compareSortedMediaTypes(
e1.getConsumeTypes(),
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java?rev=722988&r1=722987&r2=722988&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
Wed Dec 3 10:04:20 2008
@@ -21,7 +21,6 @@
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -38,68 +37,63 @@
public static final String TEMPLATE_PARAMETERS =
"jaxrs.template.parameters";
public static final String LIMITED_REGEX_SUFFIX = "(/.*)?";
- public static final String UNLIMITED_REGEX_SUFFIX = "(/)?";
public static final String FINAL_MATCH_GROUP = "FINAL_MATCH_GROUP";
/**
* The regular expression for matching URI templates and names.
*/
private static final Pattern TEMPLATE_NAMES_PATTERN =
- Pattern.compile("\\{(\\w[-\\w\\.]*)\\}");
-
- /**
- * A URI template is converted into a regular expression by substituting
- * (.*?) for each occurrence of {\([w- 14 \. ]+?\)} within the URL
- * template
- */
- private static final String PATH_VARIABLE_REGEX = "([^/]+?)";
- private static final String PATH_UNLIMITED_VARIABLE_REGEX = "(.*?)";
+ Pattern.compile("\\{(\\w[-\\w\\.]*)(\\:(.+?))?\\}");
+ private static final String DEFAULT_PATH_VARIABLE_REGEX = "([^/]+?)";
+
private final String template;
- private final List<String> templateVariables;
+ private final List<String> templateVariables = new ArrayList<String>();
+ private final List<String> customTemplateVariables = new
ArrayList<String>();
private final Pattern templateRegexPattern;
private final String literals;
- public URITemplate(String theTemplate) {
- this(theTemplate, true);
- }
- public URITemplate(String theTemplate, boolean limited) {
+ public URITemplate(String theTemplate) {
+
this.template = theTemplate;
StringBuilder literalChars = new StringBuilder();
- StringBuilder stringBuilder = new StringBuilder();
- List<String> names = new ArrayList<String>();
-
+ StringBuilder patternBuilder = new StringBuilder();
+
// compute a regular expression from URI template
Matcher matcher = TEMPLATE_NAMES_PATTERN.matcher(template);
int i = 0;
while (matcher.find()) {
- literalChars.append(template.substring(i, matcher.start()));
- copyURITemplateCharacters(template, i, matcher.start(),
stringBuilder);
+ templateVariables.add(matcher.group(1).trim());
+
+ String substr = escapeCharacters(template.substring(i,
matcher.start()));
+ literalChars.append(substr);
+ patternBuilder.append(substr);
i = matcher.end();
- if (!limited && i == template.length()) {
- stringBuilder.append(PATH_UNLIMITED_VARIABLE_REGEX);
+ if (matcher.group(2) != null && matcher.group(3) != null) {
+ patternBuilder.append('(');
+ patternBuilder.append(matcher.group(3).trim());
+ patternBuilder.append(')');
+ customTemplateVariables.add(matcher.group(1).trim());
} else {
- stringBuilder.append(PATH_VARIABLE_REGEX);
- }
- names.add(matcher.group(1));
+ patternBuilder.append(DEFAULT_PATH_VARIABLE_REGEX);
+ }
}
- literalChars.append(template.substring(i, template.length()));
- copyURITemplateCharacters(template, i, template.length(),
stringBuilder);
+ String substr = escapeCharacters(template.substring(i,
template.length()));
+ literalChars.append(substr);
+ patternBuilder.append(substr);
literals = literalChars.toString();
- templateVariables = Collections.unmodifiableList(names);
-
- int endPos = stringBuilder.length() - 1;
- boolean endsWithSlash = (endPos >= 0) ? stringBuilder.charAt(endPos)
== '/' : false;
+ int endPos = patternBuilder.length() - 1;
+ boolean endsWithSlash = (endPos >= 0) ? patternBuilder.charAt(endPos)
== '/' : false;
if (endsWithSlash) {
- stringBuilder.deleteCharAt(endPos);
+ patternBuilder.deleteCharAt(endPos);
}
- stringBuilder.append(limited ? LIMITED_REGEX_SUFFIX :
UNLIMITED_REGEX_SUFFIX);
+ patternBuilder.append(LIMITED_REGEX_SUFFIX);
- templateRegexPattern = Pattern.compile(stringBuilder.toString());
+ templateRegexPattern = Pattern.compile(patternBuilder.toString());
}
public String getLiteralChars() {
@@ -114,15 +108,21 @@
return templateVariables.size();
}
- private void copyURITemplateCharacters(String templateValue, int start,
int end, StringBuilder b) {
- for (int i = start; i < end; i++) {
- char c = templateValue.charAt(i);
- if (c == '?') {
- b.append("\\?");
- } else {
- b.append(c);
- }
+ public int getNumberOfGroupsWithCustomExpression() {
+ return customTemplateVariables.size();
+ }
+
+ private static String escapeCharacters(String expression) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < expression.length(); i++) {
+ char ch = expression.charAt(i);
+ sb.append(isReservedCharater(ch) ? "\\" + ch : ch);
}
+ return sb.toString();
+ }
+
+ private static boolean isReservedCharater(char ch) {
+ return '.' == ch;
}
public boolean match(String uri, MultivaluedMap<String, String>
templateVariableToValue) {
Modified:
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java?rev=722988&r1=722987&r2=722988&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriInfoImplTest.java
Wed Dec 3 10:04:20 2008
@@ -122,7 +122,7 @@
// with suffix
values.clear();
- new URITemplate("/bar", false).match("/bar", values);
+ new URITemplate("/bar").match("/bar", values);
u = new UriInfoImpl(mockMessage("http://localhost:8080/baz", "/bar"),
values);
Modified:
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java?rev=722988&r1=722987&r2=722988&view=diff
==============================================================================
---
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java
(original)
+++
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/URITemplateTest.java
Wed Dec 3 10:04:20 2008
@@ -35,8 +35,7 @@
@Test
public void testMatchBasic() throws Exception {
- URITemplate uriTemplate = new URITemplate("/customers/{id}",
- false);
+ URITemplate uriTemplate = new URITemplate("/customers/{id}");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers/123/", values);
@@ -47,8 +46,7 @@
@Test
public void testMatchWithMatrixAndTemplate() throws Exception {
- URITemplate uriTemplate = new URITemplate("/customers/{id}",
- false);
+ URITemplate uriTemplate = new URITemplate("/customers/{id}");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers/123;123456/", values);
@@ -59,8 +57,7 @@
@Test
public void testMatchWithMatrixOnClearPath1() throws Exception {
- URITemplate uriTemplate = new URITemplate("/customers/{id}",
- false);
+ URITemplate uriTemplate = new URITemplate("/customers/{id}");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers;123456/123/", values);
@@ -71,8 +68,7 @@
@Test
public void testMatchWithMatrixOnClearPath2() throws Exception {
- URITemplate uriTemplate = new
URITemplate("/customers/{id}/orders/{order}",
- false);
+ URITemplate uriTemplate = new
URITemplate("/customers/{id}/orders/{order}");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
assertTrue(uriTemplate.match("/customers;123456/123/orders;456/3",
values));
@@ -82,8 +78,7 @@
@Test
public void testMatchWithMatrixOnClearPath3() throws Exception {
- URITemplate uriTemplate = new URITemplate("/{id}/customers/",
- false);
+ URITemplate uriTemplate = new URITemplate("/{id}/customers/");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/123/customers;123456/", values);
@@ -94,8 +89,7 @@
@Test
public void testMatchBasicTwoParametersVariation1() throws Exception {
- URITemplate uriTemplate = new
URITemplate("/customers/{name}/{department}",
- false);
+ URITemplate uriTemplate = new
URITemplate("/customers/{name}/{department}");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers/john/CS", values);
@@ -108,8 +102,7 @@
@Test
public void testMatchBasicTwoParametersVariation2() throws Exception {
- URITemplate uriTemplate = new
URITemplate("/customers/name/{name}/dep/{department}",
- false);
+ URITemplate uriTemplate = new
URITemplate("/customers/name/{name}/dep/{department}");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers/name/john/dep/CS",
values);
@@ -123,7 +116,7 @@
@Test
public void testURITemplateWithSubResource() throws Exception {
//So "/customers" is the URITemplate for the root resource class
- URITemplate uriTemplate = new URITemplate("/customers", true);
+ URITemplate uriTemplate = new URITemplate("/customers");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers/123", values);
@@ -135,7 +128,7 @@
@Test
public void testURITemplateWithSubResourceVariation2() throws Exception {
//So "/customers" is the URITemplate for the root resource class
- URITemplate uriTemplate = new URITemplate("/customers", true);
+ URITemplate uriTemplate = new URITemplate("/customers");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/customers/name/john/dep/CS",
values);
@@ -150,7 +143,7 @@
* public Book getBook(@UriParam("bookId") String id)
*/
public void testURITemplateWithSubResourceVariation3() throws Exception {
- URITemplate uriTemplate = new URITemplate("/books/{bookId}/", true);
+ URITemplate uriTemplate = new URITemplate("/books/{bookId}/");
MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
boolean match = uriTemplate.match("/books/123/chapter/1", values);
@@ -158,4 +151,119 @@
String subResourcePath =
values.getFirst(URITemplate.FINAL_MATCH_GROUP);
assertEquals("/chapter/1", subResourcePath);
}
+
+ @Test
+ public void testBasicCustomExpression() throws Exception {
+ URITemplate uriTemplate = new URITemplate("/books/{bookId:[^/]+?}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ boolean match = uriTemplate.match("/books/123/chapter/1", values);
+ assertTrue(match);
+ assertEquals("123", values.getFirst("bookId"));
+ String subResourcePath =
values.getFirst(URITemplate.FINAL_MATCH_GROUP);
+ assertEquals("/chapter/1", subResourcePath);
+ }
+
+ @Test
+ public void testBasicCustomExpression2() throws Exception {
+ URITemplate uriTemplate = new URITemplate("/books/{bookId:123}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ boolean match = uriTemplate.match("/books/123/chapter/1", values);
+ assertTrue(match);
+ assertEquals("123", values.getFirst("bookId"));
+ String subResourcePath =
values.getFirst(URITemplate.FINAL_MATCH_GROUP);
+ assertEquals("/chapter/1", subResourcePath);
+ }
+
+ @Test
+ public void testBasicCustomExpression3() throws Exception {
+ URITemplate uriTemplate = new URITemplate("/books/{bookId:\\d\\d\\d}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ boolean match = uriTemplate.match("/books/123/chapter/1", values);
+ assertTrue(match);
+ assertEquals("123", values.getFirst("bookId"));
+ String subResourcePath =
values.getFirst(URITemplate.FINAL_MATCH_GROUP);
+ assertEquals("/chapter/1", subResourcePath);
+ }
+
+ @Test
+ public void testEscaping() throws Exception {
+ URITemplate uriTemplate = new URITemplate("/books/a.db");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ assertTrue(uriTemplate.match("/books/a.db", values));
+ assertFalse(uriTemplate.match("/books/adbc", values));
+ assertFalse(uriTemplate.match("/books/acdb", values));
+
+ }
+
+ @Test
+ public void testBasicCustomExpression4() throws Exception {
+ URITemplate uriTemplate = new URITemplate("/books/{bookId:...\\.}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ assertTrue(uriTemplate.match("/books/123.", values));
+ assertEquals("123.", values.getFirst("bookId"));
+ values.clear();
+ assertTrue(uriTemplate.match("/books/abc.", values));
+ assertEquals("abc.", values.getFirst("bookId"));
+ assertFalse(uriTemplate.match("/books/abcd", values));
+ assertFalse(uriTemplate.match("/books/abc", values));
+ }
+
+ @Test
+ public void testMultipleExpression2() throws Exception {
+ URITemplate uriTemplate = new
URITemplate("/books/{bookId:123}/chapter/{id}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ boolean match = uriTemplate.match("/books/123/chapter/1", values);
+ assertTrue(match);
+ assertEquals("123", values.getFirst("bookId"));
+ assertEquals("1", values.getFirst("id"));
+ String subResourcePath =
values.getFirst(URITemplate.FINAL_MATCH_GROUP);
+ assertEquals("/", subResourcePath);
+ }
+
+ @Test
+ public void testFailCustomExpression() throws Exception {
+ URITemplate uriTemplate = new URITemplate("/books/{bookId:124}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+
+ boolean match = uriTemplate.match("/books/123/chapter/1", values);
+ assertFalse(match);
+ }
+
+ @Test
+ public void testBaseTail1() {
+ URITemplate uriTemplate = new URITemplate("/{base:base.+}/{tail}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+ assertFalse(uriTemplate.match("/base/tails", values));
+ assertTrue(uriTemplate.match("/base1/tails", values));
+ assertEquals("base1", values.getFirst("base"));
+ assertEquals("tails", values.getFirst("tail"));
+ }
+
+ @Test
+ public void testBaseTail2() {
+ URITemplate uriTemplate = new URITemplate("/{base:.+base}/{tail}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+ assertFalse(uriTemplate.match("/base/tails", values));
+ assertFalse(uriTemplate.match("/base1/tails", values));
+ assertTrue(uriTemplate.match("/1base/tails", values));
+ assertEquals("1base", values.getFirst("base"));
+ assertEquals("tails", values.getFirst("tail"));
+ }
+
+ @Test
+ public void testBaseTail3() {
+ URITemplate uriTemplate = new
URITemplate("/{base:base.+suffix}/{tail}");
+ MultivaluedMap<String, String> values = new MetadataMap<String,
String>();
+ assertFalse(uriTemplate.match("/base/tails", values));
+ assertFalse(uriTemplate.match("/base1/tails", values));
+ assertTrue(uriTemplate.match("/base1suffix/tails", values));
+ assertEquals("base1suffix", values.getFirst("base"));
+ assertEquals("tails", values.getFirst("tail"));
+ }
}
Modified:
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java?rev=722988&r1=722987&r2=722988&view=diff
==============================================================================
---
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
(original)
+++
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStore.java
Wed Dec 3 10:04:20 2008
@@ -51,7 +51,7 @@
import org.apache.cxf.helpers.XMLUtils;
[EMAIL PROTECTED]("/bookstore/")
[EMAIL PROTECTED]("/bookstore")
public class BookStore {
private Map<Long, Book> books = new HashMap<Long, Book>();
@@ -139,6 +139,12 @@
}
@GET
+ @Path("books/custom/{bookId:\\d\\d\\d}")
+ public Book getBookCustom(@PathParam("bookId") String id) throws
BookNotFoundFault {
+ return doGetBook(id);
+ }
+
+ @GET
@Path("/books/query")
public Book getBookQuery(@QueryParam("bookId") long id) throws
BookNotFoundFault {
return doGetBook(Long.toString(id));
Modified:
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
URL:
http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java?rev=722988&r1=722987&r2=722988&view=diff
==============================================================================
---
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
(original)
+++
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java
Wed Dec 3 10:04:20 2008
@@ -184,6 +184,13 @@
}
@Test
+ public void testGetBookCustomExpression() throws Exception {
+
getAndCompareAsStrings("http://localhost:9080/bookstore/books/custom/123",
+ "resources/expected_get_book123.txt",
+ "application/xml", 200);
+ }
+
+ @Test
public void testGetBook123() throws Exception {
getAndCompareAsStrings("http://localhost:9080/bookstore/books/123",
"resources/expected_get_book123.txt",