Author: lukaszlenart Date: Fri Mar 15 14:02:12 2013 New Revision: 1456961 URL: http://svn.apache.org/r1456961 Log: WW-3998 Extracts interface and adds default implementation base on existing code
Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/OgnlTextParser.java struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParser.java Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/StrutsResultSupport.java struts/struts2/trunk/core/src/main/resources/struts-default.xml struts/struts2/trunk/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java struts/struts2/trunk/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java Fri Mar 15 14:02:12 2013 @@ -247,4 +247,6 @@ public final class StrutsConstants { public static final String STRUTS_CONVERTER_CREATOR = "struts.converter.creator"; public static final String STRUTS_CONVERTER_HOLDER = "struts..converter.holder"; + public static final String STRUTS_EXPRESSION_PARSER = "struts.expression.parser"; + } Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/config/BeanSelectionProvider.java Fri Mar 15 14:02:12 2013 @@ -49,10 +49,7 @@ import com.opensymphony.xwork2.inject.Co import com.opensymphony.xwork2.inject.Context; import com.opensymphony.xwork2.inject.Factory; import com.opensymphony.xwork2.inject.Scope; -import com.opensymphony.xwork2.util.ClassLoaderUtil; -import com.opensymphony.xwork2.util.LocalizedTextUtil; -import com.opensymphony.xwork2.util.PatternMatcher; -import com.opensymphony.xwork2.util.ValueStackFactory; +import com.opensymphony.xwork2.util.*; import com.opensymphony.xwork2.util.location.LocatableProperties; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; @@ -276,6 +273,13 @@ import java.util.StringTokenizer; * <td>singleton</td> * <td>Holds user converters' instances</td> * </tr> + * <tr> + * <td>com.opensymphony.xwork2.util.TextParser</td> + * <td>struts.expression.parser</td> + * <td>singleton</td> + * <td>Used to parse expressions like ${foo.bar} or %{bar.foo} but it is up tp the TextParser's + * implementation what kind of opening char to use (#, $, %, etc)</td> + * </tr> * </table> * * <!-- END SNIPPET: extensionPoints --> @@ -355,6 +359,8 @@ public class BeanSelectionProvider imple alias(UnknownHandlerManager.class, StrutsConstants.STRUTS_UNKNOWN_HANDLER_MANAGER, builder, props); alias(UrlHelper.class, StrutsConstants.STRUTS_URL_HELPER, builder, props); + alias(TextParser.class, StrutsConstants.STRUTS_EXPRESSION_PARSER, builder, props); + if ("true".equalsIgnoreCase(props.getProperty(StrutsConstants.STRUTS_DEVMODE))) { props.setProperty(StrutsConstants.STRUTS_I18N_RELOAD, "true"); props.setProperty(StrutsConstants.STRUTS_CONFIGURATION_XML_RELOAD, "true"); Modified: struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/StrutsResultSupport.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/StrutsResultSupport.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/StrutsResultSupport.java (original) +++ struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/StrutsResultSupport.java Fri Mar 15 14:02:12 2013 @@ -197,13 +197,13 @@ public abstract class StrutsResultSuppor if (parse && param != null && invocation != null) { return TextParseUtil.translateVariables(param, invocation.getStack(), new TextParseUtil.ParsedValueEvaluator() { - public Object evaluate(Object parsedValue) { + public Object evaluate(String parsedValue) { if (encode) { if (parsedValue != null) { try { // use UTF-8 as this is the recommended encoding by W3C to // avoid incompatibilities. - return URLEncoder.encode(parsedValue.toString(), "UTF-8"); + return URLEncoder.encode(parsedValue, "UTF-8"); } catch(UnsupportedEncodingException e) { if (LOG.isWarnEnabled()) { 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=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/core/src/main/resources/struts-default.xml (original) +++ struts/struts2/trunk/core/src/main/resources/struts-default.xml Fri Mar 15 14:02:12 2013 @@ -100,6 +100,8 @@ <bean class="com.opensymphony.xwork2.ognl.OgnlUtil" /> + <bean type="com.opensymphony.xwork2.util.TextParser" name="struts" class="com.opensymphony.xwork2.util.OgnlTextParser" scope="singleton"/> + <bean type="ognl.PropertyAccessor" name="com.opensymphony.xwork2.util.CompoundRoot" class="com.opensymphony.xwork2.ognl.accessor.CompoundRootAccessor" /> <bean type="ognl.PropertyAccessor" name="java.lang.Object" class="com.opensymphony.xwork2.ognl.accessor.ObjectAccessor" /> <bean type="ognl.PropertyAccessor" name="java.util.Iterator" class="com.opensymphony.xwork2.ognl.accessor.XWorkIteratorPropertyAccessor" /> Modified: struts/struts2/trunk/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java (original) +++ struts/struts2/trunk/plugins/embeddedjsp/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java Fri Mar 15 14:02:12 2013 @@ -25,6 +25,8 @@ import com.opensymphony.xwork2.FileManag import com.opensymphony.xwork2.FileManagerFactory; import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.util.TextParser; +import com.opensymphony.xwork2.util.OgnlTextParser; import com.opensymphony.xwork2.util.ValueStack; import com.opensymphony.xwork2.util.finder.ClassLoaderInterface; import com.opensymphony.xwork2.util.finder.ClassLoaderInterfaceDelegate; @@ -275,6 +277,8 @@ public class EmbeddedJSPResultTest exten //mock container Container container = EasyMock.createNiceMock(Container.class); EasyMock.expect(container.getInstance(XWorkConverter.class)).andReturn(converter).anyTimes(); + TextParser parser = new OgnlTextParser(); + EasyMock.expect(container.getInstance(TextParser.class)).andReturn(parser).anyTimes(); EasyMock.expect(container.getInstanceNames(FileManager.class)).andReturn(new HashSet<String>()).anyTimes(); EasyMock.expect(container.getInstance(FileManager.class)).andReturn(fileManager).anyTimes(); Modified: struts/struts2/trunk/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java (original) +++ struts/struts2/trunk/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java Fri Mar 15 14:02:12 2013 @@ -24,10 +24,12 @@ package org.apache.struts2.views.java.si import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.conversion.impl.XWorkConverter; import com.opensymphony.xwork2.inject.Container; +import com.opensymphony.xwork2.util.TextParser; +import com.opensymphony.xwork2.util.OgnlTextParser; import com.opensymphony.xwork2.util.ValueStack; import junit.framework.TestCase; -import org.apache.struts2.StrutsConstants; import org.apache.struts2.ServletActionContext; +import org.apache.struts2.StrutsConstants; import org.apache.struts2.components.Component; import org.apache.struts2.components.UIBean; import org.apache.struts2.components.template.Template; @@ -107,6 +109,8 @@ public abstract class AbstractTest exten XWorkConverter converter = new ConverterEx(); EasyMock.expect(container.getInstance(String.class, StrutsConstants.STRUTS_TAG_ALTSYNTAX)).andReturn("true").anyTimes(); EasyMock.expect(container.getInstance(XWorkConverter.class)).andReturn(converter).anyTimes(); + TextParser parser = new OgnlTextParser(); + EasyMock.expect(container.getInstance(TextParser.class)).andReturn(parser).anyTimes(); stackContext.put(ActionContext.CONTAINER, container); Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java Fri Mar 15 14:02:12 2013 @@ -52,10 +52,7 @@ import com.opensymphony.xwork2.ognl.acce import com.opensymphony.xwork2.ognl.accessor.XWorkListPropertyAccessor; import com.opensymphony.xwork2.ognl.accessor.XWorkMapPropertyAccessor; import com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor; -import com.opensymphony.xwork2.util.CompoundRoot; -import com.opensymphony.xwork2.util.PatternMatcher; -import com.opensymphony.xwork2.util.ValueStackFactory; -import com.opensymphony.xwork2.util.WildcardHelper; +import com.opensymphony.xwork2.util.*; import com.opensymphony.xwork2.util.fs.DefaultFileManager; import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory; import com.opensymphony.xwork2.util.location.LocatableProperties; @@ -137,6 +134,8 @@ public class XWorkConfigurationProvider .factory(MethodAccessor.class, Object.class.getName(), XWorkMethodAccessor.class, Scope.SINGLETON) .factory(MethodAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON) + .factory(TextParser.class, OgnlTextParser.class, Scope.SINGLETON) + .factory(NullHandler.class, Object.class.getName(), InstantiatingNullHandler.class, Scope.SINGLETON) .factory(ActionValidatorManager.class, AnnotationActionValidatorManager.class, Scope.SINGLETON) .factory(ActionValidatorManager.class, "no-annotations", DefaultActionValidatorManager.class, Scope.SINGLETON) Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java Fri Mar 15 14:02:12 2013 @@ -332,7 +332,7 @@ public class ParametersInterceptor exten String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor.class, "devmode.notification", ActionContext.getContext().getLocale(), "Developer Notification:\n{0}", new Object[]{ "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage() }); - LOG.error(developerNotification); + LOG.error(developerNotification, e); if (action instanceof ValidationAware) { ((ValidationAware) action).addActionMessage(developerNotification); } Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/OgnlTextParser.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/OgnlTextParser.java?rev=1456961&view=auto ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/OgnlTextParser.java (added) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/OgnlTextParser.java Fri Mar 15 14:02:12 2013 @@ -0,0 +1,84 @@ +package com.opensymphony.xwork2.util; + +import org.apache.commons.lang3.StringUtils; + +/** + * OGNL implementation of {@link TextParser} + */ +public class OgnlTextParser implements TextParser { + + public Object evaluate(char[] openChars, String expression, TextParseUtil.ParsedValueEvaluator evaluator, int maxLoopCount) { + // deal with the "pure" expressions first! + //expression = expression.trim(); + Object result = expression; + for (char open : openChars) { + int loopCount = 1; + int pos = 0; + + //this creates an implicit StringBuffer and shouldn't be used in the inner loop + final String lookupChars = open + "{"; + + while (true) { + int start = expression.indexOf(lookupChars, pos); + if (start == -1) { + pos = 0; + loopCount++; + start = expression.indexOf(lookupChars); + } + if (loopCount > maxLoopCount) { + // translateVariables prevent infinite loop / expression recursive evaluation + break; + } + int length = expression.length(); + int x = start + 2; + int end; + char c; + int count = 1; + while (start != -1 && x < length && count != 0) { + c = expression.charAt(x++); + if (c == '{') { + count++; + } else if (c == '}') { + count--; + } + } + end = x - 1; + + if ((start != -1) && (end != -1) && (count == 0)) { + String var = expression.substring(start + 2, end); + + Object o = evaluator.evaluate(var); + + String left = expression.substring(0, start); + String right = expression.substring(end + 1); + String middle = null; + if (o != null) { + middle = o.toString(); + if (StringUtils.isEmpty(left)) { + result = o; + } else { + result = left.concat(middle); + } + + if (StringUtils.isNotEmpty(right)) { + result = result.toString().concat(right); + } + + expression = left.concat(middle).concat(right); + } else { + // the variable doesn't exist, so don't display anything + expression = left.concat(right); + result = expression; + } + pos = (left != null && left.length() > 0 ? left.length() - 1: 0) + + (middle != null && middle.length() > 0 ? middle.length() - 1: 0) + + 1; + pos = Math.max(pos, 1); + } else { + break; + } + } + } + return result; + } +} Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java (original) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java Fri Mar 15 14:02:12 2013 @@ -22,8 +22,6 @@ import com.opensymphony.xwork2.inject.Co import java.util.HashSet; import java.util.Set; -import org.apache.commons.lang3.StringUtils; - /** * Utility class for text parsing. @@ -153,84 +151,26 @@ public class TextParseUtil { * @param evaluator * @return Converted object from variable translation. */ - public static Object translateVariables(char[] openChars, String expression, ValueStack stack, Class asType, ParsedValueEvaluator evaluator, int maxLoopCount) { - // deal with the "pure" expressions first! - //expression = expression.trim(); - Object result = expression; - for (char open : openChars) { - int loopCount = 1; - int pos = 0; - - //this creates an implicit StringBuffer and shouldn't be used in the inner loop - final String lookupChars = open + "{"; - - while (true) { - int start = expression.indexOf(lookupChars, pos); - if (start == -1) { - pos = 0; - loopCount++; - start = expression.indexOf(lookupChars); - } - if (loopCount > maxLoopCount) { - // translateVariables prevent infinite loop / expression recursive evaluation - break; - } - int length = expression.length(); - int x = start + 2; - int end; - char c; - int count = 1; - while (start != -1 && x < length && count != 0) { - c = expression.charAt(x++); - if (c == '{') { - count++; - } else if (c == '}') { - count--; - } - } - end = x - 1; + public static Object translateVariables(char[] openChars, String expression, final ValueStack stack, final Class asType, final ParsedValueEvaluator evaluator, int maxLoopCount) { - if ((start != -1) && (end != -1) && (count == 0)) { - String var = expression.substring(start + 2, end); - Object o = stack.findValue(var, asType); - if (evaluator != null) { - o = evaluator.evaluate(o); - } - - - String left = expression.substring(0, start); - String right = expression.substring(end + 1); - String middle = null; - if (o != null) { - middle = o.toString(); - if (StringUtils.isEmpty(left)) { - result = o; - } else { - result = left.concat(middle); - } - - if (StringUtils.isNotEmpty(right)) { - result = result.toString().concat(right); - } - - expression = left.concat(middle).concat(right); - } else { - // the variable doesn't exist, so don't display anything - expression = left.concat(right); - result = expression; - } - pos = (left != null && left.length() > 0 ? left.length() - 1: 0) + - (middle != null && middle.length() > 0 ? middle.length() - 1: 0) + - 1; - pos = Math.max(pos, 1); - } else { - break; + ParsedValueEvaluator ognlEval = new ParsedValueEvaluator() { + public Object evaluate(String parsedValue) { + Object o = stack.findValue(parsedValue, asType); + if (evaluator != null) { + o = evaluator.evaluate(o.toString()); } + return o; } - } + }; + + + TextParser parser = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(TextParser.class); XWorkConverter conv = ((Container)stack.getContext().get(ActionContext.CONTAINER)).getInstance(XWorkConverter.class); + + Object result = parser.evaluate(openChars, expression, ognlEval, maxLoopCount); + return conv.convertValue(stack.getContext(), result, asType); } @@ -279,6 +219,6 @@ public class TextParseUtil { * @param parsedValue - value parsed by ognl value stack * @return return the evaluted value. */ - Object evaluate(Object parsedValue); + Object evaluate(String parsedValue); } } Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParser.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParser.java?rev=1456961&view=auto ============================================================================== --- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParser.java (added) +++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParser.java Fri Mar 15 14:02:12 2013 @@ -0,0 +1,11 @@ +package com.opensymphony.xwork2.util; + +/** + * Used to parse expressions like ${foo.bar} or %{bar.foo} but it is up tp the TextParser's + * implementation what kind of opening char to use (#, $, %, etc) + */ +public interface TextParser { + + Object evaluate(char[] openChars, String expression, TextParseUtil.ParsedValueEvaluator evaluator, int maxLoopCount); + +} Modified: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java?rev=1456961&r1=1456960&r2=1456961&view=diff ============================================================================== --- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java (original) +++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java Fri Mar 15 14:02:12 2013 @@ -40,7 +40,7 @@ public class TextParseUtilTest extends X }); TextParseUtil.ParsedValueEvaluator evaluator = new TextParseUtil.ParsedValueEvaluator() { - public Object evaluate(Object parsedValue) { + public Object evaluate(String parsedValue) { return parsedValue.toString()+"Something"; } }; @@ -53,7 +53,7 @@ public class TextParseUtilTest extends X public void testTranslateVariables() { ValueStack stack = ActionContext.getContext().getValueStack(); - Object s = TextParseUtil.translateVariables("foo: ${{1, 2, 3}}, bar: ${1}", stack); + Object s = TextParseUtil.translateVariables("foo: ${{1, 2, 3}}, bar: %{1}", stack); assertEquals("foo: [1, 2, 3], bar: 1", s); s = TextParseUtil.translateVariables("foo: %{{1, 2, 3}}, bar: %{1}", stack);