Merging of SWF-367 back into trunk. This has all of the SWF 2.0 goodies.

This commit is contained in:
Ben Hale
2007-10-11 01:16:37 +00:00
parent b9513cd42b
commit 58d1ea3acc
984 changed files with 11849 additions and 39596 deletions

View File

@@ -18,15 +18,12 @@ package org.springframework.binding.convert.support;
import org.springframework.binding.convert.ConversionContext;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.binding.expression.support.StaticExpression;
import org.springframework.util.Assert;
/**
* Converter that converts a String into an Expression object.
*
* @see org.springframework.binding.expression.Expression
* @see org.springframework.binding.expression.SettableExpression
*
* @author Erwin Vervaet
*/
@@ -58,15 +55,11 @@ public class TextToExpression extends AbstractConverter {
}
public Class[] getTargetClasses() {
return new Class[] { Expression.class, SettableExpression.class };
return new Class[] { Expression.class };
}
protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
String expressionString = (String) source;
if (getExpressionParser().isDelimitedExpression(expressionString)) {
return getExpressionParser().parseExpression((String) source);
} else {
return new StaticExpression(expressionString);
}
return expressionParser.parseExpression(expressionString, Object.class, Object.class, null);
}
}

View File

@@ -34,21 +34,14 @@ public class EvaluationAttempt {
*/
private Object target;
/**
* The evaluation context.
*/
private EvaluationContext context;
/**
* Create an evaluation attempt.
* @param expression the expression that failed to evaluate
* @param target the target of the expression
* @param context the context attributes that might have affected evaluation behavior
*/
public EvaluationAttempt(Expression expression, Object target, EvaluationContext context) {
public EvaluationAttempt(Expression expression, Object target) {
this.expression = expression;
this.target = target;
this.context = context;
}
/**
@@ -65,18 +58,11 @@ public class EvaluationAttempt {
return target;
}
/**
* Returns context attributes that may have influenced the evaluation process.
*/
public EvaluationContext getContext() {
return context;
}
public String toString() {
return createToString(new ToStringCreator(this)).toString();
}
protected ToStringCreator createToString(ToStringCreator creator) {
return creator.append("expression", expression).append("target", target).append("context", context);
return creator.append("expression", expression).append("target", target);
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed 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.springframework.binding.expression;
import java.util.Map;
/**
* A context object with two main responsibities:
* <ol>
* <li>Exposing information to an expression to influence an evaluation attempt.
* <li>Providing operations for recording progress or errors during the expression evaluation process.
* </ol>
*
* @author Keith Donald
*/
public interface EvaluationContext {
/**
* Returns a map of attributes that can be used to influence expression evaluation.
* @return the evaluation attributes
*/
public Map getAttributes();
}

View File

@@ -27,9 +27,16 @@ public interface Expression {
* Evaluate the expression encapsulated by this evaluator against the provided target object and return the result
* of the evaluation.
* @param target the target of the expression
* @param context the expression evaluation context
* @return the evaluation result
* @throws EvaluationException an exception occured during evaluation
*/
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException;
public Object getValue(Object target) throws EvaluationException;
/**
* Evaluate this expression against the target object to set its value to the value provided.
* @param target the target object
* @param value the new value to be set
* @throws EvaluationException an exception occurred during evaluation
*/
public void setValue(Object target, Object value) throws EvaluationException;
}

View File

@@ -16,7 +16,7 @@
package org.springframework.binding.expression;
/**
* Parses expression strings, returing a configured evaluator instance capable of performing parsed expression
* Parses expression strings, returning a configured evaluator instance capable of performing parsed expression
* evaluation in a thread safe way.
*
* @author Keith Donald
@@ -24,30 +24,38 @@ package org.springframework.binding.expression;
public interface ExpressionParser {
/**
* Is this expression string delimited in a manner that indicates it is a parseable expression? For example
* "${expression}".
* @param expressionString the proposed expression string
* @return true if yes, false if not
* Is the provided expression string an "eval" expression: meaning an expression that validates to a dynamic value,
* and not a literal expression? "Eval" expressions are normally enclosed in delimiters like #{}, where literal
* expressions are not delimited.
* @param string the string
* @return true if the expression is an eval expression string, false otherwise.
*/
public boolean isDelimitedExpression(String expressionString);
public boolean isEvalExpressionString(String string);
/**
* Parse the provided expression string, returning an evaluator capable of evaluating it against input.
* @param expressionString the parseable expression string
* @return the evaluator for the parsed expression
* @throws ParserException an exception occured during parsing
* Parse the raw string into an "eval" expression string that when parsed produces a dynamic value when evaluated
* against a target object. For example, the raw expression string "person.id" might become #{person.id}. If the
* string is already an eval expression string, the string argument is returned unchanged. If the string is an
* composite expression string that mixes eval and literal expressions, a parser exception is thrown.
* @param string the raw string to be transformed into a parseable eval expression string
* @return the eval expression spring
* @throws ParserException an exception occurred during parsing
*/
public Expression parseExpression(String expressionString) throws ParserException;
public String parseEvalExpressionString(String string) throws ParserException;
/**
* Parse the provided settable expression string, returning an evaluator capable of evaluating its value as well as
* setting its value.
* Parse the provided expression string, returning an expression evaluator capable of evaluating it. The expression
* string may be a literal expression string like "foo", an eval-expression string like #{foo}, or a
* composite-expression string like "foo#{foo}bar#{bar}".
* @param expressionString the parseable expression string
* @param expressionTargetType the class of target object this expression can successfully evaluate; for example,
* <code>Map.class</code> for an expression that is expected to evaluate against Maps.
* @param expectedEvaluationResultType the class of object this expression is expected to return or set: for
* example, <code>Boolean.class</code> for an expression that is expected to get or set a boolean value.
* @param expressionVariables variables providing aliases for this expression during evaluation parsing. Optional.
* @return the evaluator for the parsed expression
* @throws ParserException an exception occured during parsing
* @throws UnsupportedOperationException this parser does not support settable expressions
* @throws ParserException an exception occurred during parsing
*/
public SettableExpression parseSettableExpression(String expressionString) throws ParserException,
UnsupportedOperationException;
public Expression parseExpression(String expressionString, Class expressionTargetType,
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException;
}

View File

@@ -0,0 +1,61 @@
package org.springframework.binding.expression;
import org.springframework.util.Assert;
/**
* A simple, convenient alias for a more-complex expression.
*
* TODO - consider making the valueExpressionString a parsed Expression object for more flexibility.
*
* @author Keith Donald
*/
public class ExpressionVariable {
private String name;
private String valueExpressionString;
/**
* Creates a new expression variable
* @param name the name of the variable, acting as an convenient alias
* @param valueExpressionString the complex expression to be aliased in string form
*/
public ExpressionVariable(String name, String valueExpressionString) {
Assert.hasText(name, "The expression variable must be named");
Assert.hasText(valueExpressionString, "The expression value expression string is required");
this.name = name;
this.valueExpressionString = valueExpressionString;
}
/**
* Returns the variable name, typically vary simple like "index".
* @return the variable name
*/
public String getName() {
return name;
}
/**
* Returns the expression that will be evaluated when the variable is referenced by its name in another expression.
* @return the expression value.
*/
public String getValueExpressionString() {
return valueExpressionString;
}
public boolean equals(Object o) {
if (!(o instanceof ExpressionVariable)) {
return false;
}
ExpressionVariable var = (ExpressionVariable) o;
return name.equals(var.name);
}
public int hashCode() {
return name.hashCode();
}
public String toString() {
return "[Expression Variable '" + name + "']";
}
}

View File

@@ -34,10 +34,9 @@ public class SetValueAttempt extends EvaluationAttempt {
* @param expression the settable expression
* @param target the target of the expression
* @param value the value that was attempted to be set
* @param context context attributes that may have influenced the evaluation and set process
*/
public SetValueAttempt(SettableExpression expression, Object target, Object value, EvaluationContext context) {
super(expression, target, context);
public SetValueAttempt(Expression expression, Object target, Object value) {
super(expression, target);
this.value = value;
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed 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.springframework.binding.expression;
/**
* An evaluator that is capable of setting a value on a target object at the path defined by this expression.
*
* @author Keith Donald
*/
public interface SettableExpression extends Expression {
/**
* Evaluate this expression against the target object to set its value to the value provided.
* @param target the target object
* @param value the new value to be set
* @param context the evaluation context
* @throws EvaluationException an exception occured during evaluation
*/
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException;
}

View File

@@ -1,54 +0,0 @@
package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;
/**
* A default {@link ELContextFactory} for facilitating use of EL for expression evaluation.
* @author Jeremy Grelle
*
*/
public class DefaultELContextFactory implements ELContextFactory {
/**
* Configures and returns a simple EL context to use to parse EL expressions.
* @return The configured simple ELContext instance.
*/
public ELContext getParseContext() {
return new SimpleELContext();
}
/**
* Configures and returns a simple EL context to use to evaluate EL expressions on the given base target object.
* @return The configured simple ELContext instance.
*/
public ELContext getEvaluationContext(Object target) {
return new SimpleELContext(target);
}
private static class SimpleELContext extends ELContext {
private DefaultELResolver resolver = new DefaultELResolver();
public SimpleELContext() {
}
public SimpleELContext(Object target) {
this.resolver.setTarget(target);
}
public ELResolver getELResolver() {
return resolver;
}
public FunctionMapper getFunctionMapper() {
return null;
}
public VariableMapper getVariableMapper() {
return null;
}
}
}

View File

@@ -1,17 +1,17 @@
package org.springframework.binding.expression.el;
import java.util.Iterator;
import java.util.List;
import javax.el.ArrayELResolver;
import javax.el.BeanELResolver;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.ListELResolver;
import javax.el.MapELResolver;
import javax.el.PropertyNotFoundException;
import javax.el.PropertyNotWritableException;
import javax.el.ResourceBundleELResolver;
import org.springframework.binding.collection.MapAdaptable;
/**
* A generic ELResolver to be used as a default when no other ELResolvers have been configured by the client
* application.
@@ -27,55 +27,48 @@ public class DefaultELResolver extends CompositeELResolver {
private Object target;
public DefaultELResolver() {
configureResolvers();
}
public Class getType(ELContext context, Object base, Object property) {
return super.getType(context, adaptIfNecessary(base), property);
}
public Object getValue(ELContext context, Object base, Object property) {
if (base == null) {
try {
return super.getValue(context, target, property);
} catch (PropertyNotFoundException ex) {
context.setPropertyResolved(false);
}
}
return super.getValue(context, adaptIfNecessary(base), property);
}
public void setValue(ELContext context, Object base, Object property, Object val) {
if (base == null) {
try {
super.setValue(context, target, property, val);
if (context.isPropertyResolved())
return;
} catch (PropertyNotWritableException ex) {
context.setPropertyResolved(false);
}
}
super.setValue(context, adaptIfNecessary(base), property, val);
/**
* Creates a new default EL resolver for resolving properties of the root object.
* @param target the target, or "root", object of the expression
*/
public DefaultELResolver(Object target, List customResolvers) {
this.target = target;
configureResolvers(customResolvers);
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = adaptIfNecessary(target);
public Class getType(ELContext context, Object base, Object property) {
return super.getType(context, base, property);
}
private Object adaptIfNecessary(Object base) {
if (base instanceof MapAdaptable) {
return ((MapAdaptable) base).asMap();
public Object getValue(ELContext context, Object base, Object property) {
if (base == null) {
return super.getValue(context, target, property);
} else {
return base;
return super.getValue(context, base, property);
}
}
private void configureResolvers() {
public void setValue(ELContext context, Object base, Object property, Object val) {
if (base == null) {
super.setValue(context, target, property, val);
} else {
super.setValue(context, base, property, val);
}
}
private void configureResolvers(List customResolvers) {
if (customResolvers != null) {
Iterator i = customResolvers.iterator();
while (i.hasNext()) {
ELResolver resolver = (ELResolver) i.next();
add(resolver);
}
}
add(new MapAdaptableELResolver());
add(new ArrayELResolver());
add(new ListELResolver());
add(new MapELResolver());
@@ -83,4 +76,4 @@ public class DefaultELResolver extends CompositeELResolver {
add(new BeanELResolver());
}
}
}

View File

@@ -2,6 +2,7 @@ package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.VariableMapper;
/**
* A factory for creating a EL context object that will be used to evaluate a target object of an EL expression.
@@ -10,19 +11,14 @@ import javax.el.ELResolver;
*/
public interface ELContextFactory {
/**
* Configures and returns an {@link ELContext} to be used in parsing EL expressions.
* @return ELContext The configured ELContext instance for parsing expressions.
*/
public ELContext getParseContext();
/**
* Configures and returns an {@link ELContext} to be used in evaluating EL expressions on the given base target
* object. In certain environments the target will be null and the base object of the expression is expected to be
* resolved via the ELContext's {@link ELResolver} chain.
* @param target The base object for the expression evaluation.
* @param target The base object for the expression evaluation
* @param variableMapper The mapping storing variables needed during expression evaluation
* @return ELContext The configured ELContext instance for evaluating expressions.
*/
public ELContext getEvaluationContext(Object target);
public ELContext getELContext(Object target, VariableMapper variableMapper);
}

View File

@@ -3,68 +3,60 @@ package org.springframework.binding.expression.el;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import org.springframework.binding.expression.EvaluationAttempt;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.binding.expression.Expression;
import org.springframework.util.Assert;
/**
* Evaluates a parsed EL expression.
*
* @author Jeremy Grelle
*/
public class ELExpression implements SettableExpression {
public class ELExpression implements Expression {
private ELContextFactory factory;
private ELContextFactory elContextFactory;
private ValueExpression expression;
private ValueExpression valueExpression;
public ELExpression(ELContextFactory factory, ValueExpression expression) {
this.factory = factory;
this.expression = expression;
}
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException {
ELContext ctx = getELContext(target);
try {
expression.setValue(ctx, value);
} catch (ELException ex) {
throw new EvaluationException(new EvaluationAttempt(this, target, context), ex);
}
}
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
ELContext ctx = getELContext(target);
try {
return expression.getValue(ctx);
} catch (ELException ex) {
throw new EvaluationException(new EvaluationAttempt(this, target, context), ex);
}
}
protected Class getType(Object target, EvaluationContext context) throws EvaluationException {
ELContext ctx = getELContext(target);
try {
return expression.getType(ctx);
} catch (ELException ex) {
throw new EvaluationException(new EvaluationAttempt(this, target, context), ex);
}
}
private VariableMapper variableMapper;
/**
* Retrieves an {@link ELContext} instance, configured with a DefaultELResolver if no other resolvers have been
* configured.
*
* @return {@link ELContext} The thread-bound {@link ELContext} instance.
* Creates a new el expression
* @param factory the el context factory for creating the EL context that will be used during expression evaluation
* @param valueExpression the value expression to evaluate
* @param variableMapper the variable mapper containing variables needed during expression evaluation
*/
protected ELContext getELContext(Object target) {
ELContext ctx = factory.getEvaluationContext(target);
return ctx;
public ELExpression(ELContextFactory factory, ValueExpression valueExpression, VariableMapper variableMapper) {
Assert.notNull(factory, "The ELContextFactory is required to evaluate EL expressions");
Assert.notNull(valueExpression, "The EL value expression is required for evaluation");
this.elContextFactory = factory;
this.valueExpression = valueExpression;
this.variableMapper = variableMapper;
}
public Object getValue(Object target) throws EvaluationException {
ELContext ctx = elContextFactory.getELContext(target, variableMapper);
try {
return valueExpression.getValue(ctx);
} catch (ELException ex) {
throw new EvaluationException(new EvaluationAttempt(this, target), ex);
}
}
public void setValue(Object target, Object value) throws EvaluationException {
ELContext ctx = elContextFactory.getELContext(target, variableMapper);
try {
valueExpression.setValue(ctx, value);
} catch (ELException ex) {
throw new EvaluationException(new EvaluationAttempt(this, target), ex);
}
}
public int hashCode() {
return expression.hashCode();
return valueExpression.hashCode();
}
public boolean equals(Object o) {
@@ -72,11 +64,11 @@ public class ELExpression implements SettableExpression {
return false;
}
ELExpression other = (ELExpression) o;
return expression.equals(other.expression);
return valueExpression.equals(other.valueExpression);
}
public String toString() {
return expression.getExpressionString();
return valueExpression.getExpressionString();
}
}
}

View File

@@ -1,13 +1,20 @@
package org.springframework.binding.expression.el;
import java.util.HashMap;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.FunctionMapper;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ExpressionVariable;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.SettableExpression;
/**
* An expression parser that parses EL expressions.
@@ -16,90 +23,118 @@ import org.springframework.binding.expression.SettableExpression;
public class ELExpressionParser implements ExpressionParser {
/**
* The expression prefix for deferred EL expressions.
* The expression prefix.
*/
private static final String DEFERRED_EL_EXPRESSION_PREFIX = "#{";
private static final String EXPRESSION_PREFIX = "#{";
/**
* The expression suffix for deferred EL expressions.
* The expression suffix.
*/
private static final String DEFERRED_EL_EXPRESSION_SUFFIX = "}";
/**
* The marked expression delimiter prefix.
*/
private String expressionPrefix = DEFERRED_EL_EXPRESSION_PREFIX;
/**
* The marked expression delimiter suffix.
*/
private String expressionSuffix = DEFERRED_EL_EXPRESSION_SUFFIX;
/**
* The {@link ELContextFactory} for retrieving a configured ELContext.
*/
private ELContextFactory contextFactory;
private static final String EXPRESSION_SUFFIX = "}";
/**
* The ExpressionFactory for constructing EL expressions
*/
private ExpressionFactory expressionFactory;
private Map contextFactories = new HashMap();
/**
* Creates a new EL expression parser for standalone usage.
*/
public ELExpressionParser(ExpressionFactory expressionFactory) {
this.expressionFactory = expressionFactory;
this.contextFactory = new DefaultELContextFactory();
}
/**
* Creates a new EL expression parser with a custom context factory for a specific environment.
*
* @param contextFactory the context factory
* Register the ELContextFactory for expressions that evaluate the given class of target object.
* @param expressionTargetType the expression target class
* @param contextFactory the context factory to use for expressions that evaluate those types of targets
*/
public ELExpressionParser(ExpressionFactory expressionFactory, ELContextFactory contextFactory) {
this.expressionFactory = expressionFactory;
this.contextFactory = contextFactory;
public void putContextFactory(Class expressionTargetType, ELContextFactory contextFactory) {
this.contextFactories.put(expressionTargetType, contextFactory);
}
/**
* Check whether or not given criteria are expressed as an expression.
*/
public boolean isDelimitedExpression(String expressionString) {
int prefixIndex = expressionString.indexOf(expressionPrefix);
if (prefixIndex == -1) {
return false;
}
int suffixIndex = expressionString.indexOf(expressionSuffix, prefixIndex);
if (suffixIndex == -1) {
return false;
} else {
if (suffixIndex == prefixIndex + expressionPrefix.length()) {
return false;
} else {
return true;
}
}
public boolean isEvalExpressionString(String expressionString) {
return expressionString.startsWith(EXPRESSION_PREFIX) && expressionString.endsWith(EXPRESSION_SUFFIX);
}
public final Expression parseExpression(String expressionString) throws ParserException {
return parseSettableExpression(expressionString);
public String parseEvalExpressionString(String string) {
return encloseInDelimitersIfNecessary(string);
}
/**
* Parses the expression string into an EL value expression.
* @param expressionString
* @throws ParserException
*/
public final SettableExpression parseSettableExpression(String expressionString) throws ParserException,
UnsupportedOperationException {
ELContext ctx = contextFactory.getParseContext();
public Expression parseExpression(String expressionString, Class expressionTargetType,
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
ParserELContext context = new ParserELContext();
try {
return new ELExpression(contextFactory, expressionFactory.createValueExpression(ctx, expressionString,
Object.class));
context.mapVariables(expressionVariables, expressionFactory);
ValueExpression expression = expressionFactory.createValueExpression(context, expressionString,
expectedEvaluationResultType);
ELContextFactory contextFactory = getContextFactory(expressionString, expressionTargetType);
return new ELExpression(contextFactory, expression, context.getVariableMapper());
} catch (ELException ex) {
throw new ParserException(expressionString, ex);
}
}
private String encloseInDelimitersIfNecessary(String expressionString) {
if (isEvalExpressionString(expressionString)) {
return expressionString;
} else {
return EXPRESSION_PREFIX + expressionString + EXPRESSION_SUFFIX;
}
}
private ELContextFactory getContextFactory(String expressionString, Class expressionTargetType) {
if (!contextFactories.containsKey(expressionTargetType)) {
throw new ParserException(expressionString, new IllegalArgumentException(
"No ELContextFactory registered for expressionTargetType [" + expressionTargetType + "]"));
}
return (ELContextFactory) contextFactories.get(expressionTargetType);
}
private static class ParserELContext extends ELContext {
private VariableMapper variableMapper;
public ELResolver getELResolver() {
return null;
}
public FunctionMapper getFunctionMapper() {
return null;
}
public VariableMapper getVariableMapper() {
return variableMapper;
}
public void mapVariables(ExpressionVariable[] variables, ExpressionFactory expressionFactory) {
if (variables != null && variables.length > 0) {
variableMapper = new VariableMapperImpl();
for (int i = 0; i < variables.length; i++) {
ExpressionVariable var = variables[i];
ValueExpression expr = expressionFactory.createValueExpression(this,
var.getValueExpressionString(), Object.class);
variableMapper.setVariable(var.getName(), expr);
}
}
}
}
private static class VariableMapperImpl extends VariableMapper {
private Map variables = new HashMap();
public ValueExpression resolveVariable(String name) {
return (ValueExpression) variables.get(name);
}
public ValueExpression setVariable(String name, ValueExpression value) {
return (ValueExpression) variables.put(name, value);
}
public String toString() {
return variables.toString();
}
}
}

View File

@@ -0,0 +1,52 @@
package org.springframework.binding.expression.el;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.MapELResolver;
import org.springframework.binding.collection.MapAdaptable;
/**
* An {@link ELResolver} for properly resolving variables in an instance of {@link MapAdaptable}
* @author Jeremy Grelle
*/
public class MapAdaptableELResolver extends MapELResolver {
public Class getType(ELContext context, Object base, Object property) {
if (base instanceof MapAdaptable) {
return super.getType(context, adapt(base), property);
} else {
return null;
}
}
public Object getValue(ELContext context, Object base, Object property) {
if (base instanceof MapAdaptable) {
return super.getValue(context, adapt(base), property);
} else {
return null;
}
}
public boolean isReadOnly(ELContext context, Object base, Object property) {
if (base instanceof MapAdaptable) {
return super.isReadOnly(context, adapt(base), property);
} else {
return false;
}
}
public void setValue(ELContext context, Object base, Object property, Object value) {
if (base instanceof MapAdaptable) {
super.setValue(context, adapt(base), property, value);
}
}
private Map adapt(Object base) {
MapAdaptable adaptable = (MapAdaptable) base;
return adaptable.asMap();
}
}

View File

@@ -16,16 +16,14 @@
package org.springframework.binding.expression.ognl;
import java.util.Collections;
import java.util.Map;
import ognl.Ognl;
import ognl.OgnlException;
import org.springframework.binding.expression.EvaluationAttempt;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.SetValueAttempt;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.util.Assert;
/**
@@ -36,7 +34,7 @@ import org.springframework.util.Assert;
*
* @author Keith Donald
*/
class OgnlExpression implements SettableExpression {
class OgnlExpression implements Expression {
/**
* The expression.
@@ -65,29 +63,29 @@ class OgnlExpression implements SettableExpression {
return expression.equals(other.expression);
}
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
public Object getValue(Object target) throws EvaluationException {
Assert.notNull(target, "The target object to evaluate is required");
Map contextAttributes = (context != null ? context.getAttributes() : Collections.EMPTY_MAP);
try {
return Ognl.getValue(expression, contextAttributes, target);
// TODO context map
return Ognl.getValue(expression, Collections.EMPTY_MAP, target);
} catch (OgnlException e) {
if (e.getReason() != null && e.getReason() != e) {
// unwrap the OgnlException since the actual exception is wrapped inside it
// and there is not generic (getCause) way to get to it later on
throw new EvaluationException(new EvaluationAttempt(this, target, context), e.getReason());
throw new EvaluationException(new EvaluationAttempt(this, target), e.getReason());
} else {
throw new EvaluationException(new EvaluationAttempt(this, target, context), e);
throw new EvaluationException(new EvaluationAttempt(this, target), e);
}
}
}
public void evaluateToSet(Object target, Object value, EvaluationContext context) {
public void setValue(Object target, Object value) {
Assert.notNull(target, "The target object to evaluate is required");
Map contextAttributes = (context != null ? context.getAttributes() : Collections.EMPTY_MAP);
try {
Ognl.setValue(expression, contextAttributes, target, value);
// TODO context map
Ognl.setValue(expression, Collections.EMPTY_MAP, target, value);
} catch (OgnlException e) {
throw new EvaluationException(new SetValueAttempt(this, target, value, context), e);
throw new EvaluationException(new SetValueAttempt(this, target, value), e);
}
}

View File

@@ -22,7 +22,6 @@ import ognl.PropertyAccessor;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.binding.expression.support.AbstractExpressionParser;
/**
@@ -33,10 +32,6 @@ import org.springframework.binding.expression.support.AbstractExpressionParser;
public class OgnlExpressionParser extends AbstractExpressionParser {
protected Expression doParseExpression(String expressionString) throws ParserException {
return doParseSettableExpression(expressionString);
}
public SettableExpression doParseSettableExpression(String expressionString) throws ParserException {
try {
return new OgnlExpression(Ognl.parseExpression(expressionString));
} catch (OgnlException e) {

View File

@@ -20,8 +20,8 @@ import java.util.List;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ExpressionVariable;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.util.StringUtils;
/**
@@ -80,27 +80,17 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
this.expressionSuffix = expressionSuffix;
}
/**
* Check whether or not given criteria are expressed as an expression.
*/
public boolean isDelimitedExpression(String expressionString) {
int prefixIndex = expressionString.indexOf(getExpressionPrefix());
if (prefixIndex == -1) {
return false;
}
int suffixIndex = expressionString.indexOf(getExpressionSuffix(), prefixIndex);
if (suffixIndex == -1) {
return false;
} else {
if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
return false;
} else {
return true;
}
}
public boolean isEvalExpressionString(String string) {
return string.startsWith(expressionPrefix) && string.endsWith(expressionSuffix);
}
public final Expression parseExpression(String expressionString) throws ParserException {
public String parseEvalExpressionString(String string) {
return encloseInDelimitersIfNecessary(string);
}
public Expression parseExpression(String expressionString, Class expressionTargetType,
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
// TODO variables
Expression[] expressions = parseExpressions(expressionString);
if (expressions.length == 1) {
return expressions[0];
@@ -109,15 +99,12 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
}
}
public final SettableExpression parseSettableExpression(String expressionString) throws ParserException,
UnsupportedOperationException {
expressionString = expressionString.trim();
// a settable expression should just be a single expression
if (expressionString.startsWith(getExpressionPrefix()) && expressionString.endsWith(getExpressionSuffix())) {
expressionString = expressionString.substring(getExpressionPrefix().length(), expressionString.length()
- getExpressionSuffix().length());
private String encloseInDelimitersIfNecessary(String expressionString) {
if (isEvalExpressionString(expressionString)) {
return expressionString;
} else {
return expressionPrefix + expressionString + expressionSuffix;
}
return doParseSettableExpression(expressionString);
}
/**
@@ -191,14 +178,4 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
*/
protected abstract Expression doParseExpression(String expressionString) throws ParserException;
/**
* Template method for parsing a filtered settable expression string. Subclasses should override.
* @param expressionString the expression string
* @return the parsed expression
* @throws ParserException an exception occured during parsing
* @throws UnsupportedOperationException this parser does not support settable expressions
*/
protected abstract SettableExpression doParseSettableExpression(String expressionString) throws ParserException,
UnsupportedOperationException;
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed 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.springframework.binding.expression.support;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.binding.expression.EvaluationAttempt;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.SetValueAttempt;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.util.Assert;
/**
* An expression evaluator that uses the Spring bean wrapper.
*
* @author Keith Donald
*/
class BeanWrapperExpression implements SettableExpression {
/**
* The expression.
*/
private String expression;
public BeanWrapperExpression(String expression) {
this.expression = expression;
}
public int hashCode() {
return expression.hashCode();
}
public boolean equals(Object o) {
if (!(o instanceof BeanWrapperExpression)) {
return false;
}
BeanWrapperExpression other = (BeanWrapperExpression) o;
return expression.equals(other.expression);
}
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
try {
return new BeanWrapperImpl(target).getPropertyValue(expression);
} catch (BeansException e) {
throw new EvaluationException(new EvaluationAttempt(this, target, context), e);
}
}
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException {
try {
Assert.notNull(target, "The target object to evaluate is required");
new BeanWrapperImpl(target).setPropertyValue(expression, value);
} catch (BeansException e) {
throw new EvaluationException(new SetValueAttempt(this, target, value, context), e);
}
}
public String toString() {
return expression;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2004-2007 the original author or authors.
*
* Licensed 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.springframework.binding.expression.support;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ParserException;
import org.springframework.binding.expression.SettableExpression;
/**
* An expression parser that parses bean wrapper expressions.
*
* @author Keith Donald
*/
public class BeanWrapperExpressionParser extends AbstractExpressionParser {
protected Expression doParseExpression(String expressionString) throws ParserException {
return doParseSettableExpression(expressionString);
}
public SettableExpression doParseSettableExpression(String expressionString) throws ParserException {
return new BeanWrapperExpression(expressionString);
}
}

View File

@@ -17,11 +17,9 @@ package org.springframework.binding.expression.support;
import java.util.Collection;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.SetValueAttempt;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@@ -30,7 +28,7 @@ import org.springframework.util.Assert;
*
* @author Keith Donald
*/
public class CollectionAddingExpression implements SettableExpression {
public class CollectionAddingExpression implements Expression {
/**
* The expression that resolves a mutable collection reference.
@@ -45,14 +43,14 @@ public class CollectionAddingExpression implements SettableExpression {
this.collectionExpression = collectionExpression;
}
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
return collectionExpression.evaluate(target, context);
public Object getValue(Object target) throws EvaluationException {
return collectionExpression.getValue(target);
}
public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException {
Object result = evaluate(target, context);
public void setValue(Object target, Object value) throws EvaluationException {
Object result = getValue(target);
if (result == null) {
throw new EvaluationException(new SetValueAttempt(this, target, value, null), new IllegalArgumentException(
throw new EvaluationException(new SetValueAttempt(this, target, value), new IllegalArgumentException(
"The collection expression evaluated to a [null] reference"));
}
Assert.isInstanceOf(Collection.class, result, "Not a collection: ");

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.binding.expression.support;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.core.style.ToStringCreator;
@@ -41,14 +40,18 @@ public class CompositeStringExpression implements Expression {
this.expressions = expressions;
}
public Object evaluate(Object target, EvaluationContext evaluationContext) throws EvaluationException {
public Object getValue(Object target) throws EvaluationException {
StringBuffer buffer = new StringBuffer(128);
for (int i = 0; i < expressions.length; i++) {
buffer.append(expressions[i].evaluate(target, evaluationContext));
buffer.append(expressions[i].getValue(target));
}
return buffer.toString();
}
public void setValue(Object target, Object value) throws EvaluationException {
throw new UnsupportedOperationException("Cannot set a composite string expression value");
}
public String toString() {
return new ToStringCreator(this).append("expressions", expressions).toString();
}

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.binding.expression.support;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.EvaluationException;
import org.springframework.binding.expression.Expression;
import org.springframework.util.ObjectUtils;
@@ -25,7 +24,7 @@ import org.springframework.util.ObjectUtils;
*
* @author Keith Donald
*/
public class StaticExpression implements Expression {
public final class StaticExpression implements Expression {
/**
* The value expression.
@@ -56,10 +55,14 @@ public class StaticExpression implements Expression {
return ObjectUtils.nullSafeEquals(value, other.value);
}
public Object evaluate(Object target, EvaluationContext context) throws EvaluationException {
public Object getValue(Object target) throws EvaluationException {
return value;
}
public void setValue(Object target, Object value) throws EvaluationException {
this.value = value;
}
public String toString() {
return String.valueOf(value);
}

View File

@@ -19,7 +19,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@@ -41,7 +40,7 @@ public class Mapping implements AttributeMapper {
/**
* The target expression to set on a target object to map to.
*/
private final SettableExpression targetExpression;
private final Expression targetExpression;
/**
* A type converter to apply during the mapping process.
@@ -59,7 +58,7 @@ public class Mapping implements AttributeMapper {
* @param targetExpression the target expression
* @param typeConverter a type converter
*/
public Mapping(Expression sourceExpression, SettableExpression targetExpression, ConversionExecutor typeConverter) {
public Mapping(Expression sourceExpression, Expression targetExpression, ConversionExecutor typeConverter) {
this(sourceExpression, targetExpression, typeConverter, false);
}
@@ -70,8 +69,8 @@ public class Mapping implements AttributeMapper {
* @param typeConverter a type converter
* @param required whether or not this mapping is required
*/
protected Mapping(Expression sourceExpression, SettableExpression targetExpression,
ConversionExecutor typeConverter, boolean required) {
protected Mapping(Expression sourceExpression, Expression targetExpression, ConversionExecutor typeConverter,
boolean required) {
Assert.notNull(sourceExpression, "The source expression is required");
Assert.notNull(targetExpression, "The target expression is required");
this.sourceExpression = sourceExpression;
@@ -88,7 +87,7 @@ public class Mapping implements AttributeMapper {
*/
public void map(Object source, Object target, MappingContext context) {
// get source value
Object sourceValue = sourceExpression.evaluate(source, null);
Object sourceValue = sourceExpression.getValue(source);
if (sourceValue == null) {
if (required) {
throw new RequiredMappingException("This mapping is required; evaluation of expression '"
@@ -108,7 +107,7 @@ public class Mapping implements AttributeMapper {
logger.debug("Mapping '" + sourceExpression + "' value [" + sourceValue + "] to target property '"
+ targetExpression + "'; setting property value to [" + targetValue + "]");
}
targetExpression.evaluateToSet(target, targetValue, null);
targetExpression.setValue(target, targetValue);
}
public boolean equals(Object o) {

View File

@@ -20,7 +20,6 @@ import org.springframework.binding.convert.ConversionService;
import org.springframework.binding.convert.support.DefaultConversionService;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.SettableExpression;
import org.springframework.binding.expression.support.CollectionAddingExpression;
import org.springframework.util.Assert;
@@ -61,7 +60,7 @@ public class MappingBuilder {
/**
* The target mapping settable expression.
*/
private SettableExpression targetExpression;
private Expression targetExpression;
/**
* The type of the object returned by evaluating the source expression.
@@ -102,7 +101,7 @@ public class MappingBuilder {
* @return this, to support call-chaining
*/
public MappingBuilder source(String expressionString) {
sourceExpression = expressionParser.parseExpression(expressionString);
sourceExpression = expressionParser.parseExpression(expressionString, Object.class, Object.class, null);
return this;
}
@@ -112,7 +111,7 @@ public class MappingBuilder {
* @return this, to support call-chaining
*/
public MappingBuilder target(String expressionString) {
targetExpression = (SettableExpression) expressionParser.parseExpression(expressionString);
targetExpression = expressionParser.parseExpression(expressionString, Object.class, Object.class, null);
return this;
}
@@ -122,7 +121,8 @@ public class MappingBuilder {
* @return this, to support call-chaining
*/
public MappingBuilder targetCollection(String expressionString) {
targetExpression = new CollectionAddingExpression(expressionParser.parseSettableExpression(expressionString));
targetExpression = new CollectionAddingExpression(expressionParser.parseExpression(expressionString,
Object.class, Object.class, null));
return this;
}
@@ -164,7 +164,7 @@ public class MappingBuilder {
public Mapping value() {
Assert.notNull(sourceExpression, "The source expression must be set at a minimum");
if (targetExpression == null) {
targetExpression = (SettableExpression) sourceExpression;
targetExpression = sourceExpression;
}
ConversionExecutor typeConverter = null;
if (sourceType != null) {

View File

@@ -17,7 +17,6 @@ package org.springframework.binding.mapping;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.SettableExpression;
/**
* A mapping that is required.
@@ -32,7 +31,7 @@ public class RequiredMapping extends Mapping {
* @param targetPropertyExpression the target property expression
* @param typeConverter a type converter
*/
public RequiredMapping(Expression sourceExpression, SettableExpression targetPropertyExpression,
public RequiredMapping(Expression sourceExpression, Expression targetPropertyExpression,
ConversionExecutor typeConverter) {
super(sourceExpression, targetPropertyExpression, typeConverter, true);
}

View File

@@ -0,0 +1,88 @@
package org.springframework.binding.message;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.util.Assert;
import org.springframework.util.CachingMapDecorator;
/**
* Default message context factory that simply stores messages indexed in a map by their source. Suitable for use in
* most Spring applications that use Spring message sources for message resource bundles. Holds a reference to a Spring
* message resource bundle for performing message text resolution.
*
* @author Keith Donald
*/
public class DefaultMessageContextFactory implements MessageContextFactory {
private MessageSource messageSource;
/**
* Create a new message context factory.
* @param messageSource
*/
public DefaultMessageContextFactory(MessageSource messageSource) {
Assert.notNull(messageSource, "The message source is required");
this.messageSource = messageSource;
}
public StateManageableMessageContext createMessageContext() {
return new MessageContextImpl(messageSource);
}
private static class MessageContextImpl implements StateManageableMessageContext {
private MessageSource messageSource;
private Map objectMessages = new CachingMapDecorator() {
protected Object create(Object objectId) {
return new ArrayList();
}
};
public MessageContextImpl(MessageSource messageSource) {
this.messageSource = messageSource;
}
public Serializable createMessagesMemento() {
return new HashMap(objectMessages);
}
public void restoreMessages(Serializable messagesMemento) {
this.objectMessages.putAll((Map) messagesMemento);
}
public void addMessage(MessageResolver messageResolver) {
Locale currentLocale = LocaleContextHolder.getLocale();
Message message = messageResolver.resolveMessage(messageSource, currentLocale);
List messages = (List) objectMessages.get(message.getSource());
messages.add(message);
}
public Message[] getMessages() {
List messages = new ArrayList();
Iterator i = objectMessages.keySet().iterator();
while (i.hasNext()) {
messages.addAll((List) objectMessages.get(i.next()));
}
return (Message[]) messages.toArray(new Message[messages.size()]);
}
public Message[] getMessages(Object source) {
List messages = (List) objectMessages.get(source);
return (Message[]) messages.toArray(new Message[messages.size()]);
}
public void clearMessages() {
objectMessages.clear();
}
}
}

View File

@@ -0,0 +1,57 @@
package org.springframework.binding.message;
import java.io.Serializable;
/**
* An object of communication that provides text information from a source. For example, a validation message may inform
* a web application user a business rule was violated. A messages comes from a source, has text providing the basis for
* communication, and has severity indicating the priority or intensity of the message for its receiver.
*
* @author Keith Donald
*/
public class Message implements Serializable {
private Object source;
private String text;
private Severity severity;
/**
* Creates a new message.
* @param source the source of the message
* @param text the message text
* @param severity the message severity
*/
public Message(Object source, String text, Severity severity) {
super();
this.source = source;
this.text = text;
this.severity = severity;
}
/**
* Returns the source of this message. The source is the object that sent the message.
* @return the source
*/
public Object getSource() {
return source;
}
/**
* Returns the message text. The text is the message's communication payload.
* @return the message text
*/
public String getText() {
return text;
}
/**
* Returns the severity of this message. The severity indicates the intensity or priority of the communication.
* @return the message severity
*/
public Severity getSeverity() {
return severity;
}
}

View File

@@ -0,0 +1,32 @@
package org.springframework.binding.message;
/**
* A context for recording and retrieving messages for display.
*/
public interface MessageContext {
/**
* Get all messages in this context. The messages returned should be suitable for display as-is.
* @return the messages
*/
public Message[] getMessages();
/**
* Get all messages in this context from the source provided.
* @param source the source that recorded the message
* @return the source's messages
*/
public Message[] getMessages(Object source);
/**
* Add a new message to this context.
* @param messageResolver the resolver that will resolve the message to be added
*/
public void addMessage(MessageResolver messageResolver);
/**
* Clear all messages added to this context.
*/
public void clearMessages();
}

View File

@@ -0,0 +1,16 @@
package org.springframework.binding.message;
/**
* A factory for creating message context's whose internal state can be externally managed. Encapsulates the message
* context implementation used in a given environment.
*
* @author Keith Donald
*/
public interface MessageContextFactory {
/**
* Create a new message context.
* @return the message context, initially empty, capable of having its state managed by an external care-taker.
*/
public StateManageableMessageContext createMessageContext();
}

View File

@@ -0,0 +1,24 @@
package org.springframework.binding.message;
import java.util.Locale;
import org.springframework.context.MessageSource;
/**
* A factory for a Message. Allows a Message to be internationalized and to be resolved from a
* {@link MessageSource message resource bundle}.
*
* @author Keith Donald
* @see Message
* @see MessageSource
*/
public interface MessageResolver {
/**
* Resolve the message from the message source using the current locale.
* @param messageSource the message source, an abstraction for a resource bundle
* @param locale the current locale of this request
* @return the resolved message
*/
public Message resolveMessage(MessageSource messageSource, Locale locale);
}

View File

@@ -0,0 +1,225 @@
package org.springframework.binding.message;
import java.util.Locale;
import org.springframework.context.MessageSource;
/**
* A convenient factory for creating {@link MessageResolver} objects programmatically. Often used by model code such as
* validation logic to conveniently record validation messages. Supports the production of "text" message resolvers that
* hard-code their message text, as well as message resolvers that retrieve their text from a
* {@link MessageSource message resource bundle}.
*
* @author Keith Donald
*/
public class Messages implements MessageResolver {
private Object source;
private String code;
private Severity severity;
private Object[] args;
private String defaultText;
private Messages(Object source, String code, Severity severity, Object[] args, String defaultText) {
this.source = source;
this.code = code;
this.severity = severity;
this.args = args;
this.defaultText = defaultText;
}
public Message resolveMessage(MessageSource messageSource, Locale locale) {
if (messageSource != null && (code != null && code.length() > 0)) {
return new Message(source, getMessageText(messageSource, locale), severity);
} else {
return new Message(source, defaultText, severity);
}
}
/**
* Creates a message resolver that creates a INFO {@link Message} with the text provided.
* @param text the raw message text that will be used as-is
* @return the message resolver
*/
public static Messages text(String text) {
return new Messages(null, null, Severity.INFO, null, text);
}
/**
* Creates a message resolver that creates a {@link Message} with the text and severity provided.
* @param text the raw message text that will be used as-is
* @param severity the desired message severity
* @return the message resolver
*/
public static Messages text(String text, Severity severity) {
return new Messages(null, null, severity, null, text);
}
/**
* Creates a message resolver that creates a {@link Severity#INFO info} {@link Message message} with its text
* resolved from a message bundle by using the provided message code.
* @param code the message code
* @return the message resolver
*/
public static Messages info(String code) {
return new Messages(null, code, Severity.INFO, null, null);
}
/**
* Creates a message resolver that creates a {@link Severity#WARNING warning} {@link Message message} with its text
* resolved from a message bundle by using the provided message code.
* @param code the message code
* @return the message resolver
*/
public static Messages warning(String code) {
return new Messages(null, code, Severity.WARNING, null, null);
}
/**
* Creates a message resolver that creates a {@link Severity#ERROR error} {@link Message message} with its text
* resolved from a message bundle by using the provided message code.
* @param code the message code
* @return the message resolver
*/
public static Messages error(String code) {
return new Messages(null, code, Severity.ERROR, null, null);
}
/**
* Creates a message resolver that creates a {@link Severity#INFO info} {@link Message message} with its text
* resolved from a message bundle by using the provided message code and message arguments.
* @param code the message code
* @param args the message arguments
* @return the message resolver
*/
public static Messages info(String code, Object[] args) {
return new Messages(null, code, Severity.INFO, args, null);
}
/**
* Creates a message resolver that creates a {@link Severity#WARNING warning} {@link Message message} with its text
* resolved from a message bundle by using the provided message code and message arguments.
* @param code the message code
* @param args the message arguments
* @return the message resolver
*/
public static Messages warning(String code, Object[] args) {
return new Messages(null, code, Severity.WARNING, args, null);
}
/**
* Creates a message resolver that creates a {@link Severity#ERROR error} {@link Message message} with its text
* resolved from a message bundle by using the provided message code and message arguments.
* @param code the message code
* @param args the message arguments
* @return the message resolver
*/
public static Messages error(String code, Object[] args) {
return new Messages(null, code, Severity.ERROR, args, null);
}
/**
* Creates a message resolver that creates a {@link Severity#INFO info} {@link Message message} from the source with
* the text provided.
* @param source the source of the message
* @param text the message text
* @return the message resolver
*/
public static Messages text(Object source, String text) {
return new Messages(source, null, Severity.INFO, null, text);
}
/**
* Creates a message resolver that creates a {@link Message message} from the source with the text and severity
* provided.
* @param source the source of the message
* @param text the message text
* @param severity the message severity
* @return the message resolver
*/
public static Messages text(Object source, String text, Severity severity) {
return new Messages(source, null, severity, null, text);
}
/**
* Creates a message resolver that creates a {@link Severity#INFO info} {@link Message message} from the source with
* its text resolved from a message bundle by using the provided message code.
* @param source the source of the message
* @param code the message code
* @return the message resolver
*/
public static Messages info(Object source, String code) {
return new Messages(source, code, Severity.INFO, null, null);
}
/**
* Creates a message resolver that creates a {@link Severity#WARNING warning} {@link Message message} from the
* source with its text resolved from a message bundle by using the provided message code.
* @param source the source of the message
* @param code the message code
* @return the message resolver
*/
public static Messages warning(Object source, String code) {
return new Messages(source, code, Severity.WARNING, null, null);
}
/**
* Creates a message resolver that creates a {@link Severity#ERROR error} {@link Message message} from the source
* with its text resolved from a message bundle by using the provided message code.
* @param source the source of the message
* @param code the message code
* @return the message resolver
*/
public static Messages error(Object source, String code) {
return new Messages(source, code, Severity.ERROR, null, null);
}
/**
* Creates a message resolver that creates a {@link Severity#INFO info} {@link Message message} from the source with
* its text resolved from a message bundle by using the provided message code and message arguments.
* @param source the source of the message
* @param code the message code
* @param args the message arguments
* @return the message resolver
*/
public static Messages info(Object source, String code, Object[] args) {
return new Messages(source, code, Severity.INFO, args, null);
}
/**
* Creates a message resolver that creates a {@link Severity#WARNING warning} {@link Message message} from the
* source with its text resolved from a message bundle by using the provided message code and message arguments.
* @param source the source of the message
* @param code the message code
* @param args the message arguments
* @return the message resolver
*/
public static Messages warning(Object source, String code, Object[] args) {
return new Messages(source, code, Severity.WARNING, args, null);
}
/**
* Creates a message resolver that creates a {@link Severity#ERROR error} {@link Message message} from the source
* with its text resolved from a message bundle by using the provided message code and message arguments.
* @param source the source of the message
* @param code the message code
* @param args the message arguments
* @return the message resolver
*/
public static Messages error(Object source, String code, Object[] args) {
return new Messages(source, code, Severity.ERROR, args, null);
}
private String getMessageText(MessageSource source, Locale locale) {
if (defaultText == null) {
return source.getMessage(code, args, locale);
} else {
return source.getMessage(code, args, defaultText, locale);
}
}
}

View File

@@ -0,0 +1,32 @@
package org.springframework.binding.message;
import org.springframework.core.enums.StaticLabeledEnum;
/**
* Enum exposing supported message severities.
*
* @author Keith Donald
* @see Message
*/
public class Severity extends StaticLabeledEnum {
/**
* The "Informational" severity. Used to indicate a successful operation or result.
*/
public static final Severity INFO = new Severity(0, "Info");
/**
* The "Warning" severity. Used to indicate there is a minor problem, or to inform the message receiver of possible
* misuse, or to indicate a problem may arise in the future.
*/
public static final Severity WARNING = new Severity(1, "Warning");
/**
* THe "Error" severity. Used to indicate a significant problem like a business rule violation.
*/
public static final Severity ERROR = new Severity(2, "Error");
private Severity(int code, String label) {
super(code, label);
}
}

View File

@@ -0,0 +1,26 @@
package org.springframework.binding.message;
import java.io.Serializable;
/**
* A message context whose internal state can be managed by an external care-taker. State management employs the GOF
* Memento pattern. This context can produce a serializable memento representing its internal state at any time. A
* care-taker can then use that memento at a later time to restore any context instance to a previous state.
*
* @author Keith Donald
*/
public interface StateManageableMessageContext extends MessageContext {
/**
* Create a serializable memento (token) representing a snapshot of the internal state of this message context.
* @return the messages memento
*/
public Serializable createMessagesMemento();
/**
* Set the state of this context from the memento provided. After this call, the messages in this context will match
* what is encapsulated inside the memento. Any previous state will be overridden.
* @param messagesMemento the messages memento
*/
public void restoreMessages(Serializable messagesMemento);
}

View File

@@ -70,7 +70,7 @@ public class MethodInvoker {
Object[] arguments = new Object[parameters.size()];
for (int i = 0; i < parameters.size(); i++) {
Parameter parameter = parameters.getParameter(i);
Object argument = parameter.evaluateArgument(argumentSource, null);
Object argument = parameter.evaluateArgument(argumentSource);
arguments[i] = applyTypeConversion(argument, parameter.getType());
}
Class[] parameterTypes = parameters.getTypesArray();

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.binding.method;
import org.springframework.binding.expression.EvaluationContext;
import org.springframework.binding.expression.Expression;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@@ -66,12 +65,11 @@ public class Parameter {
/**
* Evaluate this method parameter against the provided argument source, returning a single method argument value.
* @param argumentSource the meyhod argument source
* @param context the evaluation context
* @param argumentSource the method argument source
* @return the method argument value
*/
public Object evaluateArgument(Object argumentSource, EvaluationContext context) {
return name.evaluate(argumentSource, context);
public Object evaluateArgument(Object argumentSource) {
return name.getValue(argumentSource);
}
public boolean equals(Object obj) {