You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/09/25 21:08:39 UTC
svn commit: r818958 - in /struts/struts2/trunk/core: ./
src/main/java/org/apache/struts2/util/ src/main/resources/
src/test/java/org/apache/struts2/util/
Author: musachy
Date: Fri Sep 25 19:08:38 2009
New Revision: 818958
URL: http://svn.apache.org/viewvc?rev=818958&view=rev
Log:
WW-3262 improve wildcard to support regular expressions
bump xwork version
Added:
struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcher.java
struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcherExpression.java
struts/struts2/trunk/core/src/test/java/org/apache/struts2/util/RegexPatternMatcherTest.java
Modified:
struts/struts2/trunk/core/pom.xml
struts/struts2/trunk/core/src/main/resources/struts-default.xml
Modified: struts/struts2/trunk/core/pom.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/pom.xml?rev=818958&r1=818957&r2=818958&view=diff
==============================================================================
--- struts/struts2/trunk/core/pom.xml (original)
+++ struts/struts2/trunk/core/pom.xml Fri Sep 25 19:08:38 2009
@@ -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>-->
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcher.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcher.java?rev=818958&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcher.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcher.java Fri Sep 25 19:08:38 2009
@@ -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>
+ * <action name="/{bio:.+}/test/{name}" class="org.apache.struts2.showcase.UITagExample">
+ * <result>/tags/ui/example.jsp</result>
+ * </action>
+ * </pre>
+ *
+ * For this to work it is important to set the following:
+ * <pre>
+ * <constant name="struts.enable.SlashesInActionNames" value="true"/>
+ * <constant name="struts.mapper.alwaysSelectFullNamespace" value="false"/>
+ * <constant name="struts.patternMatcher" value="regex" />
+ * </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;
+ }
+ }
+
+}
Added: struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcherExpression.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcherExpression.java?rev=818958&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcherExpression.java (added)
+++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/util/RegexPatternMatcherExpression.java Fri Sep 25 19:08:38 2009
@@ -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;
+ }
+}
Modified: struts/struts2/trunk/core/src/main/resources/struts-default.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/struts-default.xml?rev=818958&r1=818957&r2=818958&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/struts-default.xml (original)
+++ struts/struts2/trunk/core/src/main/resources/struts-default.xml Fri Sep 25 19:08:38 2009
@@ -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" />
Added: struts/struts2/trunk/core/src/test/java/org/apache/struts2/util/RegexPatternMatcherTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/util/RegexPatternMatcherTest.java?rev=818958&view=auto
==============================================================================
--- struts/struts2/trunk/core/src/test/java/org/apache/struts2/util/RegexPatternMatcherTest.java (added)
+++ struts/struts2/trunk/core/src/test/java/org/apache/struts2/util/RegexPatternMatcherTest.java Fri Sep 25 19:08:38 2009
@@ -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
+ }
+ }
+
+}