From 99416e44ba1d1033247b25f4b53db1d0c129c68b Mon Sep 17 00:00:00 2001 From: Jeremy Grelle Date: Tue, 31 Jul 2007 23:33:22 +0000 Subject: [PATCH] JsfELExpressionParser and supporting classes for SWF-301, making JSF-managed beans available to expressions in the FlowDefinition via the unified EL. --- .../executor/jsf/ELResolverAdapter.java | 132 ++++++++++++++++++ .../webflow/executor/jsf/FacesAPI.java | 25 ++++ .../executor/jsf/JsfELExpressionParser.java | 63 +++++++++ 3 files changed, 220 insertions(+) create mode 100644 spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ELResolverAdapter.java create mode 100644 spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java create mode 100644 spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ELResolverAdapter.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ELResolverAdapter.java new file mode 100644 index 00000000..0cd3af18 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/ELResolverAdapter.java @@ -0,0 +1,132 @@ +package org.springframework.webflow.executor.jsf; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.PropertyNotWritableException; +import javax.faces.context.FacesContext; +import javax.faces.el.EvaluationException; +import javax.faces.el.PropertyNotFoundException; +import javax.faces.el.PropertyResolver; +import javax.faces.el.VariableResolver; + +/** + * An adapter for using JSF 1.1 {@link VariableResolver}s and {@link PropertyResolver}s in an {@link ELContext}. + * @author Jeremy Grelle + * + */ +public class ELResolverAdapter extends ELResolver { + + private FacesContext facesContext; + + public ELResolverAdapter(FacesContext facesContext) { + this.facesContext = facesContext; + } + + public Class getCommonPropertyType(ELContext context, Object base) { + return Object.class; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + return Collections.EMPTY_LIST.iterator(); + } + + public Class getType(ELContext context, Object base, Object property) { + if (property == null) { + return null; + } + try { + context.setPropertyResolved(true); + if (base == null) { + Object var = getVariableResolver().resolveVariable(facesContext, property.toString()); + return (var != null) ? var.getClass() : null; + } else { + if (base instanceof List || base.getClass().isArray()) { + return getPropertyResolver().getType(base, Integer.parseInt(property.toString())); + } else { + return getPropertyResolver().getType(base, property); + } + } + } catch (PropertyNotFoundException ex) { + throw new javax.el.PropertyNotFoundException(ex.getMessage(), ex.getCause()); + } catch (EvaluationException ex) { + throw new ELException(ex.getMessage(), ex.getCause()); + } + } + + public Object getValue(ELContext context, Object base, Object property) { + if (property == null) { + return null; + } + try { + context.setPropertyResolved(true); + if (base == null) { + return getVariableResolver().resolveVariable(facesContext, property.toString()); + } else { + if (base instanceof List || base.getClass().isArray()) { + return getPropertyResolver().getValue(base, Integer.parseInt(property.toString())); + } else { + return getPropertyResolver().getValue(base, property); + } + } + } catch (PropertyNotFoundException ex) { + throw new javax.el.PropertyNotFoundException(ex.getMessage(), ex.getCause()); + } catch (EvaluationException ex) { + throw new ELException(ex.getMessage(), ex.getCause()); + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) { + if (property == null) { + return true; + } + try { + context.setPropertyResolved(true); + if (base == null) { + return false; // VariableResolver provides no way to determine isReadOnly + } else { + if (base instanceof List || base.getClass().isArray()) { + return getPropertyResolver().isReadOnly(base, Integer.parseInt(property.toString())); + } else { + return getPropertyResolver().isReadOnly(base, property); + } + } + } catch (PropertyNotFoundException ex) { + throw new javax.el.PropertyNotFoundException(ex.getMessage(), ex.getCause()); + } catch (EvaluationException ex) { + throw new ELException(ex.getMessage(), ex.getCause()); + } + } + + public void setValue(ELContext context, Object base, Object property, Object value) { + if (property == null) { + throw new PropertyNotWritableException("Property is Null"); + } + try { + context.setPropertyResolved(true); + if (base instanceof List || base.getClass().isArray()) { + getPropertyResolver().setValue(base, Integer.parseInt(property.toString()), value); + } else { + getPropertyResolver().setValue(base, property, value); + } + + } catch (PropertyNotFoundException ex) { + throw new javax.el.PropertyNotFoundException(ex.getMessage(), ex.getCause()); + } catch (EvaluationException ex) { + throw new ELException(ex.getMessage(), ex.getCause()); + } + } + + private VariableResolver getVariableResolver() { + return facesContext.getApplication().getVariableResolver(); + } + + private PropertyResolver getPropertyResolver() { + return facesContext.getApplication().getPropertyResolver(); + } + +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java new file mode 100644 index 00000000..6482e7f2 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/FacesAPI.java @@ -0,0 +1,25 @@ +package org.springframework.webflow.executor.jsf; + +import javax.faces.application.Application; + +public class FacesAPI { + + private static final int version = specifyVersion(); + + private FacesAPI() { + + } + + private final static int specifyVersion() { + try { + Application.class.getMethod("getExpressionFactory", null); + } catch (NoSuchMethodException e) { + return 11; + } + return 12; + } + + public final static int getVersion() { + return version; + } +} diff --git a/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java new file mode 100644 index 00000000..cfe7e824 --- /dev/null +++ b/spring-webflow/src/main/java/org/springframework/webflow/executor/jsf/JsfELExpressionParser.java @@ -0,0 +1,63 @@ +package org.springframework.webflow.executor.jsf; + +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.VariableMapper; +import javax.faces.context.FacesContext; + +import org.springframework.binding.expression.el.ELContextFactory; +import org.springframework.binding.expression.el.JBossELExpressionParser; + +/** + * A JSF-aware ExpressionParser that allows JSF managed beans to be referenced in expressions in the FlowDefinition. + * @author Jeremy Grelle + * + */ +public class JsfELExpressionParser extends JBossELExpressionParser { + + public JsfELExpressionParser() { + super(new JsfELContextFactory()); + } + + public JsfELExpressionParser(ELContextFactory contextFactory) { + super(contextFactory); + } + + private static class JsfELContextFactory implements ELContextFactory { + + public ELContext getELContext(Object target) { + + FacesContext context = FacesContext.getCurrentInstance(); + if (FacesAPI.getVersion() < 12) { + return new Jsf11ELContext(context); + } + if (context != null) { + return context.getELContext(); + } + return null; + } + + private static class Jsf11ELContext extends ELContext { + + ELResolver baseResolver; + + public Jsf11ELContext(FacesContext context) { + baseResolver = new ELResolverAdapter(context); + } + + public ELResolver getELResolver() { + return baseResolver; + } + + public FunctionMapper getFunctionMapper() { + return null; + } + + public VariableMapper getVariableMapper() { + return null; + } + } + } + +}