blob: dac50b24f7dba5f9b397ede2ce31fe931eb8c4f1 [file] [log] [blame]
package org.apache.struts2.uelplugin;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.ClearableValueStack;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import javax.el.*;
import java.util.Map;
import java.util.TreeMap;
import java.util.HashMap;
import org.apache.struts2.uelplugin.elresolvers.AccessorsContextKey;
/**
* A ValueStack that uses Unified EL as the underlying Expression Language.
*/
public class UelValueStack implements ValueStack, ClearableValueStack {
private static final Logger LOG = LoggerFactory.getLogger(UelValueStack.class);
private CompoundRoot root = new CompoundRoot();
private transient Map context;
private Class defaultType;
private Map overrides;
private ELContext elContext;
private Container container;
private XWorkConverter xworkConverter;
public UelValueStack(Container container) {
this(container, new CompoundRoot());
}
public UelValueStack(Container container, ValueStack vs) {
this(container, new CompoundRoot(vs.getRoot()));
}
public UelValueStack(Container container, CompoundRoot root) {
this.container = container;
this.xworkConverter = container.getInstance(XWorkConverter.class);
setRoot(new CompoundRoot(root));
}
public String findString(String expr, boolean throwException) {
return (String) findValue(expr, String.class);
}
public String findString(String expr) {
return findString(expr, false);
}
public Object findValue(String expr) {
return findValue(expr, Object.class, false);
}
public Object findValue(String expr, boolean throwException) {
return findValue(expr, Object.class, false);
}
public Object findValue(String expr, Class asType) {
return findValue(expr, asType, false);
}
public Object findValue(String expr, Class asType, boolean throwException) {
String originalExpression = expr;
try {
if ((overrides != null) && overrides.containsKey(expr)) {
expr = (String) overrides.get(expr);
}
if (expr != null && expr.startsWith("%{")) {
// replace %{ with ${
expr = "#" + expr.substring(1);
}
if (expr != null && !expr.startsWith("${") && !expr.startsWith("#{")) {
expr = "#{" + expr + "}";
}
elContext.putContext(AccessorsContextKey.class, context);
elContext.putContext(XWorkConverter.class, xworkConverter);
elContext.putContext(CompoundRoot.class, root);
// parse our expression
ExpressionFactory factory = getExpressionFactory();
ValueExpression valueExpr = factory.createValueExpression(elContext, expr, Object.class);
Object retVal = valueExpr.getValue(elContext);
if (!Object.class.equals(asType)) {
retVal = xworkConverter.convertValue(null, retVal, asType);
}
return retVal;
} catch (PropertyNotFoundException e) {
if (context.containsKey(originalExpression)) {
return context.get(originalExpression);
}
// property not found
return null;
} catch (ELException e) {
// fail silently so we don't mess things up
return null;
}
}
protected ExpressionFactory getExpressionFactory() {
ExpressionFactory factory = ExpressionFactoryHolder.getExpressionFactory();
if (factory == null) {
String message = "********** FATAL ERROR STARTING UP STRUTS-UEL INTEGRATION **********\n" +
"Looks like the UEL listener was not configured for your web app! \n" +
"Nothing will work until UelServletContextListener is added as a listener in web.xml.\n" +
"You might need to add the following to web.xml: \n" +
" <listener>\n" +
" <listener-class>org.apache.struts2.uelplugin.UelServletContextListener</listener-class>\n" +
" </listener>";
LOG.fatal(message);
throw new IllegalStateException("Unable to find ExpressionFactory instance. Make sure that 'UelServletContextListener' " +
"is configured in web.xml as a listener");
} else
return factory;
}
public Map getContext() {
return context;
}
public Map getExprOverrides() {
return overrides;
}
public CompoundRoot getRoot() {
return root;
}
public Object peek() {
return root.peek();
}
public Object pop() {
return root.pop();
}
public void push(Object o) {
root.push(o);
}
public void setDefaultType(Class defaultType) {
this.defaultType = defaultType;
}
public void setExprOverrides(Map overrides) {
if (this.overrides == null) {
this.overrides = overrides;
} else {
this.overrides.putAll(overrides);
}
}
public void set(String key, Object o) {
overrides.put(key, o);
}
public void setValue(String expr, Object value) {
setValue(expr, value, false);
}
public void setValue(String expr, Object value, boolean throwExceptionOnFailure) {
try {
if (expr != null && !expr.startsWith("${") && !expr.startsWith("#{")) {
expr = "#{" + expr + "}";
}
elContext.putContext(AccessorsContextKey.class, context);
elContext.putContext(XWorkConverter.class, xworkConverter);
elContext.putContext(CompoundRoot.class, root);
// parse our expression
ExpressionFactory factory = getExpressionFactory();
ValueExpression valueExpr = factory.createValueExpression(elContext, expr, Object.class);
valueExpr.setValue(elContext, value);
} catch (ELException e) {
if (throwExceptionOnFailure) {
throw e;
}
}
}
public int size() {
return root.size();
}
protected void setRoot(CompoundRoot root) {
this.context = new TreeMap();
context.put(VALUE_STACK, this);
this.root = root;
elContext = new CompoundRootELContext(container);
}
public void clearContextValues() {
getContext().clear();
}
}