WW-3262 improve wildcard to support regular expressions

bump xwork version

git-svn-id: https://svn.apache.org/repos/asf/struts/struts2/trunk@818958 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Musachy Barroso
2009-09-25 19:08:38 +00:00
parent 986e389a18
commit c182a130c5
5 changed files with 334 additions and 2 deletions
+2 -2
View File
@@ -56,7 +56,7 @@
<artifactItem>
<groupId>com.opensymphony</groupId>
<artifactId>xwork-core</artifactId>
<version>2.1.6</version>
<version>2.1.7-SNAPSHOT</version>
<classifier>sources</classifier>
</artifactItem>
</artifactItems>
@@ -229,7 +229,7 @@
<dependency>
<groupId>com.opensymphony</groupId>
<artifactId>xwork-core</artifactId>
<version>2.1.6</version>
<version>2.1.7-SNAPSHOT</version>
</dependency>
<!--<dependency>-->
@@ -0,0 +1,113 @@
/*
* $Id: ServletContextAware.java 651946 2008-04-27 13:41:38Z apetrelli $
*
* 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.struts2.util;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.xwork.StringUtils;
import com.opensymphony.xwork2.util.PatternMatcher;
/**
* Allows regular expressions to be used in action names. The regular expressions
* can be in the form {FIELD_NAME} or {FIELD_NAME:REGULAR_EXPRESSION}. For example:
* <br/>
* <pre>
* &lt;action name="/{bio:.+}/test/{name}" class="org.apache.struts2.showcase.UITagExample"&gt;
* &lt;result>/tags/ui/example.jsp&lt;/result&gt;
* &lt;/action&gt;
* </pre>
*
* For this to work it is important to set the following:
* <pre>
* &lt;constant name="struts.enable.SlashesInActionNames" value="true"/&gt;
* &lt;constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/&gt;
* &lt;constant name="struts.patternMatcher" value="regex" /&gt;
* </pre>
*/
public class RegexPatternMatcher implements PatternMatcher<RegexPatternMatcherExpression> {
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
public RegexPatternMatcherExpression compilePattern(String data) {
Map<Integer, String> params = new HashMap<Integer, String>();
Matcher matcher = PATTERN.matcher(data);
int count = 0;
while (matcher.find()) {
String expression = matcher.group(1);
//check if it is a regex
int index = expression.indexOf(':');
if (index > 0) {
String paramName = expression.substring(0, index);
String regex = StringUtils.substring(expression, index + 1);
if (StringUtils.isBlank(regex)) {
throw new IllegalArgumentException("invalid expression [" + expression + "], named parameter regular exression "
+ "must be in the format {PARAM_NAME:REGEX}");
}
params.put(++count, paramName);
} else {
params.put(++count, expression);
}
}
//generate a new pattern used to match URIs
//replace {X:B} by (B)
String newPattern = data.replaceAll("(\\{.*?:(.*?)\\})", "($2)");
//replace {X} by (.*?)
newPattern = newPattern.replaceAll("(\\{.*?\\})", "(.*?)");
return new RegexPatternMatcherExpression(Pattern.compile(newPattern), params);
}
public boolean isLiteral(String pattern) {
return (pattern == null || pattern.indexOf('{') == -1);
}
public boolean match(Map<String, String> map, String data, RegexPatternMatcherExpression expr) {
Matcher matcher = expr.getPattern().matcher(data);
Map<Integer, String> params = expr.getParams();
if (matcher.matches()) {
map.put("0", data);
//extract values and get param names from the expression
for (int i = 1; i <= matcher.groupCount(); i++) {
String paramName = params.get(i);
String value = matcher.group(i);
//by name
map.put(paramName, value);
//by index so the old {1} still works
map.put(String.valueOf(i), value);
}
return true;
} else {
return false;
}
}
}
@@ -0,0 +1,49 @@
/*
* $Id: ServletContextAware.java 651946 2008-04-27 13:41:38Z apetrelli $
*
* 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.struts2.util;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Holds a compiled expression to match URLs
* @see RegexPatternMatcher
*/
public class RegexPatternMatcherExpression {
//pattern that matches the whole string
private final Pattern pattern;
//maps group index (from pattern) to parameter names
private final Map<Integer, String> params;
public RegexPatternMatcherExpression(Pattern pattern, Map<Integer, String> params) {
this.pattern = pattern;
this.params = params;
}
public Pattern getPattern() {
return pattern;
}
public Map<Integer, String> getParams() {
return params;
}
}
@@ -38,6 +38,7 @@
<bean type="com.opensymphony.xwork2.util.PatternMatcher" name="struts" class="com.opensymphony.xwork2.util.WildcardHelper" />
<bean type="com.opensymphony.xwork2.util.PatternMatcher" name="namedVariable" class="com.opensymphony.xwork2.util.NamedVariablePatternMatcher"/>
<bean type="com.opensymphony.xwork2.util.PatternMatcher" name="regex" class="org.apache.struts2.util.RegexPatternMatcher"/>
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="struts" class="org.apache.struts2.dispatcher.mapper.DefaultActionMapper" />
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="composite" class="org.apache.struts2.dispatcher.mapper.CompositeActionMapper" />
@@ -0,0 +1,169 @@
/*
* $Id: ServletContextAware.java 651946 2008-04-27 13:41:38Z apetrelli $
*
* 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.struts2.util;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import junit.framework.TestCase;
public class RegexPatternMatcherTest extends TestCase {
private RegexPatternMatcher matcher = new RegexPatternMatcher();
public void testIsLiteral() {
assertTrue(matcher.isLiteral(null));
assertTrue(matcher.isLiteral(""));
assertTrue(matcher.isLiteral(" \t"));
assertTrue(matcher.isLiteral("something"));
assertFalse(matcher.isLiteral("{"));
}
public void testCompile0() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/some/{test}");
assertNotNull(expr);
//params
Map<Integer, String> params = expr.getParams();
assertNotNull(params);
assertEquals(1, params.size());
assertEquals("test", params.get(1));
//pattern
Pattern pattern = expr.getPattern();
assertNotNull(pattern);
assertEquals("/some/(.*?)", pattern.pattern());
}
public void testCompile1() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/{test}/some/{test1}/");
assertNotNull(expr);
//params
Map<Integer, String> params = expr.getParams();
assertNotNull(params);
assertEquals(2, params.size());
assertEquals("test", params.get(1));
assertEquals("test1", params.get(2));
//pattern
Pattern pattern = expr.getPattern();
assertNotNull(pattern);
assertEquals("/(.*?)/some/(.*?)/", pattern.pattern());
}
public void testCompileNamedParams0() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/some/{test:.+}");
assertNotNull(expr);
//params
Map<Integer, String> params = expr.getParams();
assertNotNull(params);
assertEquals(1, params.size());
assertEquals("test", params.get(1));
//pattern
Pattern pattern = expr.getPattern();
assertNotNull(pattern);
assertEquals("/some/(.+)", pattern.pattern());
}
public void testCompileNamedParams1() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/some/{test1:.+}/{test2:.*}");
assertNotNull(expr);
//params
Map<Integer, String> params = expr.getParams();
assertNotNull(params);
assertEquals(2, params.size());
assertEquals("test1", params.get(1));
assertEquals("test2", params.get(2));
//pattern
Pattern pattern = expr.getPattern();
assertNotNull(pattern);
assertEquals("/some/(.+)/(.*)", pattern.pattern());
}
public void testMatch0() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/some/{test}");
Map<String, String> values = new HashMap<String, String>();
assertTrue(matcher.match(values, "/some/val", expr));
assertEquals(3, values.size());
assertEquals("val", values.get("test"));
assertEquals("val", values.get("1"));
assertEquals("/some/val", values.get("0"));
}
public void testMatch1() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/some/{test0}/some/{test1}");
Map<String, String> values = new HashMap<String, String>();
assertTrue(matcher.match(values, "/some/val0/some/val1", expr));
assertEquals(5, values.size());
assertEquals("val0", values.get("test0"));
assertEquals("val1", values.get("test1"));
assertEquals("val0", values.get("1"));
assertEquals("val1", values.get("2"));
assertEquals("/some/val0/some/val1", values.get("0"));
}
public void testMatch2() {
RegexPatternMatcherExpression expr = matcher.compilePattern("/some/{test0}/some/{test1}/.*");
Map<String, String> values = new HashMap<String, String>();
assertTrue(matcher.match(values, "/some/val0/some/val1/buaaa", expr));
assertEquals(5, values.size());
assertEquals("val0", values.get("test0"));
assertEquals("val1", values.get("test1"));
assertEquals("val0", values.get("1"));
assertEquals("val1", values.get("2"));
assertEquals("/some/val0/some/val1/buaaa", values.get("0"));
}
public void testCompileBad0() {
try {
matcher.compilePattern("/{test/some");
fail("Should have failed");
} catch (Exception e) {
//ok
}
}
public void testCompileBad1() {
try {
matcher.compilePattern("/test/{p:}");
fail("Should have failed");
} catch (Exception e) {
//ok
}
}
}