Author: andrei_exadel
Date: 2008-10-07 10:31:22 -0400 (Tue, 07 Oct 2008)
New Revision: 10680
Added:
trunk/ui/columns/src/main/java/org/richfaces/el/
trunk/ui/columns/src/main/java/org/richfaces/el/ELBuilder.java
trunk/ui/columns/src/test/java/org/richfaces/el/
trunk/ui/columns/src/test/java/org/richfaces/el/ELBuilderTest.java
Modified:
trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsHandler.java
trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsTag.java
Log:
RF-4563
Added: trunk/ui/columns/src/main/java/org/richfaces/el/ELBuilder.java
===================================================================
--- trunk/ui/columns/src/main/java/org/richfaces/el/ELBuilder.java
(rev 0)
+++ trunk/ui/columns/src/main/java/org/richfaces/el/ELBuilder.java 2008-10-07 14:31:22 UTC
(rev 10680)
@@ -0,0 +1,161 @@
+package org.richfaces.el;
+
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.ValueExpression;
+
+public class ELBuilder {
+ String orig;
+
+ StringBuffer res = new StringBuffer("#{");
+
+ int l;
+
+ String var;
+
+ String index;
+
+ String varReplacement;
+
+ String indexReplacement;
+
+ int varL;
+
+ int indexL;
+
+ public ELBuilder(String orig, String var, String index, String varR,
+ String indexR) {
+ this.orig = trimEL(orig);
+ this.var = var;
+ this.index = index;
+ this.varReplacement = varR;
+ this.indexReplacement = indexR;
+ l = this.orig.length();
+ varL = var.length();
+ indexL = index.length();
+
+ }
+
+ public String parse() {
+ internalParse(orig);
+ res.append("}");
+ return res.toString();
+ }
+
+ public static ValueExpression createValueExpression (String expr, Class<?>
expectedType,ExpressionFactory factory, ELContext elContext, String var, String index,
String varR,
+ String indexR) {
+ ELBuilder builder = new ELBuilder(expr, var, index, varR, indexR);
+ String newExpr = builder.parse();
+ return factory.createValueExpression(elContext, newExpr, expectedType);
+ }
+
+ public static String trimEL(String orig) {
+ if (orig.trim().startsWith("#")) {
+ orig = orig.substring(1).trim();
+ if (orig.startsWith("{") && orig.endsWith("}")) {
+ orig = orig.substring(1, orig.length() - 1);
+ }
+ }
+ return orig;
+ }
+
+ private int internalParse(String s) {
+
+ final char firstVar = var.charAt(0);
+ final char firstIndex = index.charAt(0);
+
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == firstIndex) {
+ i = parseIndex(i, c);
+ } else if (c == firstVar) {
+ i = parseVar(i, c);
+ } else if (isQuote(c)) {
+ i = parseString(i, c);
+ } else {
+ res.append(c);
+ }
+ }
+ return 0;
+ }
+
+ private int parseIndex(int i, char c) {
+ if (orig.indexOf(index, i) == i) {
+ Character before = (i != 0) ? orig.charAt(i - 1) : null;
+ Character after = (i + indexL < l) ? orig.charAt(i + indexL) : null;
+ if (isIndex(c, before, after)) {
+ res.append(indexReplacement);
+ return i + indexL - 1;
+ } else {
+ res.append(c);
+ return i++;
+ }
+ }
+ res.append(c);
+ return i;
+ }
+
+ private int parseVar(int i, char c) {
+ if (orig.indexOf(var, i) == i) {
+ Character before = (i != 0) ? orig.charAt(i - 1) : null;
+ Character after = (i + varL < l) ? orig.charAt(i + varL) : null;
+ if (isVar(c, before, after)) {
+ res.append(varReplacement);
+ return i + varL - 1;
+ } else {
+ res.append(c);
+ return i++;
+ }
+ }
+ res.append(c);
+ return i;
+ }
+
+ private int parseString(int i, char c) {
+ res.append(orig.charAt(i));
+ int j = i++;
+ while (j < l) {
+ if (isQuote(orig.charAt(j))) {
+ break;
+ } else {
+ res.append(orig.charAt(j));
+ }
+ j++;
+ }
+ return j;
+ }
+
+ private boolean isIndex(Character c, Character before, Character after) {
+ boolean ret = before == null
+ || (Character.isWhitespace(before) || isMath(before)
+ || before == '[' || before == '(' || before == '{');
+ if (ret) {
+ ret = after == null
+ || (Character.isWhitespace(after) || isMath(after)
+ || after == ']' || before == ')' || before == '}');
+ }
+ return ret;
+ }
+
+ private boolean isVar(Character c, Character before, Character after) {
+ boolean ret = before == null
+ || (Character.isWhitespace(before) || before == '(' || before ==
'{');
+ if (ret) {
+ ret = after == null
+ || (Character.isWhitespace(after) || after == ')'
+ || after == '(' || after == ']' || after == '[' || after
== '.');
+ }
+ return ret;
+ }
+
+ private boolean isMath(Character c) {
+ return c == '+' || c == '*' || c == '-' || c == '/' ||
c == '%'
+ || c == '(' || c == ')';
+
+ }
+
+ private boolean isQuote(Character c) {
+ return c == '\'' || c == '\"';
+ }
+
+}
Modified: trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsHandler.java
===================================================================
--- trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsHandler.java 2008-10-07
09:29:25 UTC (rev 10679)
+++ trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsHandler.java 2008-10-07
14:31:22 UTC (rev 10680)
@@ -7,6 +7,7 @@
package org.richfaces.taglib;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
@@ -20,11 +21,16 @@
import javax.faces.component.UIComponent;
import javax.servlet.jsp.JspTagException;
+import org.richfaces.el.ELBuilder;
import org.richfaces.iterator.ForEachIterator;
import org.richfaces.iterator.SimpleForEachIterator;
import com.sun.facelets.FaceletContext;
+import com.sun.facelets.tag.MetaRule;
+import com.sun.facelets.tag.MetaRuleset;
import com.sun.facelets.tag.MetaTagHandler;
+import com.sun.facelets.tag.Metadata;
+import com.sun.facelets.tag.MetadataTarget;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.jsf.ComponentConfig;
@@ -39,6 +45,17 @@
public class ColumnsHandler extends MetaTagHandler {
com.sun.facelets.tag.jsf.ComponentHandler handler;
+
+ public final static List<String> filterAttributes = new
ArrayList<String>();
+ public final static List<String> sortAttributes = new
ArrayList<String>();
+ static {
+ filterAttributes.add("filterBy");
+ filterAttributes.add("filterExpression");
+ filterAttributes.add("filterValue");
+ filterAttributes.add("filterEvent");
+
+ sortAttributes.add("sortExpression");
+ }
/** value attribute */
private TagAttribute value;
@@ -86,7 +103,23 @@
/** Expression for var item */
public IteratedExpression iteratedExpression;
+
+ public String valueExpr;
+
+ public String getVarReplacement() {
+ return valueExpr + "[" + _index + "]";
+ }
+
+ public String getIndexReplacement() {
+ return String.valueOf(_index);
+ }
};
+
+ ThreadLocal<IterationContext> iterationContextLocal = new
ThreadLocal<IterationContext>();
+
+ public IterationContext getIterationContext() {
+ return iterationContextLocal.get();
+ }
/**
* TODO Description goes here.
@@ -95,18 +128,55 @@
*/
public ColumnsHandler(ComponentConfig config) {
super(config);
- handler = new ColumnTagHandler(config);
+ handler = new ColumnTagHandler(config) {
+ @Override
+ protected MetaRuleset createMetaRuleset(Class type) {
+ MetaRuleset ruleset = super.createMetaRuleset(type);
+ ruleset.addRule(new MetaRule() {
+
+ @Override
+ public Metadata applyRule(final String name,
+ final TagAttribute attribute, MetadataTarget meta) {
+ if (filterAttributes.indexOf(name) != -1) {
+ return new Metadata() {
+
+ @Override
+ public void applyMetadata(FaceletContext ctx,
+ Object instance) {
+ if (!attribute.isLiteral()) {
+ String expr = attribute.getValue();
+ IterationContext itContext = iterationContextLocal.get();
+
+ ValueExpression ve = ELBuilder.createValueExpression(expr, Object.class,
ctx.getExpressionFactory(), ctx.getFacesContext().getELContext(),
+ itContext._itemId, itContext._indexId,
+ itContext.getVarReplacement(), itContext.getIndexReplacement());
+ ((UIComponent)instance).setValueExpression(name, ve);
+ }else {
+ ((UIComponent)instance).getAttributes().put(name, attribute.getValue());
+ }
+ }
+
+ };
+ }
+ return null;
+ }
+
+ });
+ return ruleset;
+ }
+ };
}
-
+
+
/**
* Extracts tags attributes values
*/
- private void initVariables(FaceletContext ctx, IterationContext itContext) {
- initColumnsCount(ctx, itContext);
- initIndex(ctx, itContext);
- initVar(ctx, itContext);
- initBegin(ctx, itContext);
- initEnd(ctx, itContext);
+ private void initVariables(FaceletContext ctx/*, IterationContext itContext*/) {
+ initColumnsCount(ctx/*, itContext*/);
+ initIndex(ctx/*, itContext*/);
+ initVar(ctx/*, itContext*/);
+ initBegin(ctx/*, itContext*/);
+ initEnd(ctx/*, itContext*/);
}
/**
@@ -114,13 +184,16 @@
*
* @throws JspTagException
*/
- private void prepare(FaceletContext ctx, IterationContext itContext) {
+ private void prepare(FaceletContext ctx/*, IterationContext itContext*/) {
- initVariables(ctx, itContext);
+ initVariables(ctx/*, itContext*/);
+
+ IterationContext itContext = getIterationContext();
try {
this.value = getAttribute("value");
+ itContext.valueExpr = ELBuilder.trimEL(this.value.getValue());
// produce the right sort of ForEachIterator
if (value != null) {
@@ -141,19 +214,20 @@
// TODO: handle exception
}
- correctFirst(ctx, itContext);
+ correctFirst(ctx/*, itContext*/);
}
/**
* Inits first iteration item
*/
- private void correctFirst(FaceletContext ctx, IterationContext itContext) {
+ private void correctFirst(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
if (itContext.items != null) {
if (itContext._begin > 0 && (itContext._index < itContext._begin)) {
- while ((itContext._index < itContext._begin && hasNext(itContext))) {
- next(ctx, itContext);
+ while ((itContext._index < itContext._begin && hasNext(/*itContext*/))) {
+ next(ctx/*, itContext*/);
}
- if (!hasNext(itContext)) {
+ if (!hasNext(/*itContext*/)) {
itContext._index = 0;
}
}
@@ -166,7 +240,8 @@
* @return
* @throws JspTagException
*/
- private boolean hasNext(IterationContext itContext) {
+ private boolean hasNext(/*IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
try {
if (itContext._end != 0) {
return (itContext._index < itContext._end) ? itContext.items.hasNext() : false;
@@ -185,7 +260,8 @@
* @return
* @throws JspTagException
*/
- private Object next(FaceletContext ctx, IterationContext itContext) {
+ private Object next(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
try {
Object o = itContext.items.next();
itContext._index++;
@@ -198,7 +274,8 @@
/**
* Extracts integer value from end attr
*/
- private void initColumnsCount(FaceletContext ctx, IterationContext itContext) {
+ private void initColumnsCount(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
this.columns = getAttribute("columns");
if (columns != null) {
try {
@@ -217,7 +294,8 @@
/**
* Extracts integer value from begin attr
*/
- private void initBegin(FaceletContext ctx, IterationContext itContext) {
+ private void initBegin(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
this.begin = getAttribute("begin");
if (begin != null) {
try {
@@ -242,7 +320,8 @@
/**
* Extracts integer value from end attr
*/
- private void initEnd(FaceletContext ctx, IterationContext itContext) {
+ private void initEnd(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
this.end = getAttribute("end");
if (end != null) {
try {
@@ -266,7 +345,8 @@
/**
* Extracts string value from var attr
*/
- private void initVar(FaceletContext ctx, IterationContext itContext) {
+ private void initVar(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
this.var = getAttribute("var");
if (var != null) {
try {
@@ -281,7 +361,8 @@
/**
* Extracts string value from index attr
*/
- private void initIndex(FaceletContext ctx, IterationContext itContext) {
+ private void initIndex(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
this.index = getAttribute("index");
if (index != null) {
try {
@@ -300,21 +381,22 @@
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, ELException {
IterationContext iterationContext = new IterationContext();
+ iterationContextLocal.set(iterationContext);
- prepare(ctx, iterationContext); // prepare data
+ prepare(ctx/*, iterationContext*/); // prepare data
try {
- while (hasNext(iterationContext)) { // for each
- exposeVariables(ctx, iterationContext);
+ while (hasNext(/*iterationContext*/)) { // for each
+ exposeVariables(ctx/*, iterationContext*/);
//super.apply(ctx, parent);
handler.apply(ctx, parent);
- next(ctx, iterationContext);
+ next(ctx/*, iterationContext*/);
}
} catch (Exception e) {
// TODO: handle exception
} finally {
- release(iterationContext);
- unExposeVariables(ctx, iterationContext);
+ release(/*iterationContext*/);
+ unExposeVariables(ctx/*, iterationContext*/);
}
}
@@ -325,6 +407,10 @@
//super.applyNextHandler(ctx, c);
}
+
+ private void onComponentCreated(UIComponent c) {
+
+ }
/**
@@ -332,8 +418,8 @@
*
* @throws JspTagException
*/
- private void exposeVariables(FaceletContext ctx, IterationContext itContext) {
-
+ private void exposeVariables(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
VariableMapper vm = ctx.getVariableMapper();
int k = itContext._index;
@@ -342,7 +428,7 @@
if (value != null) {
ValueExpression srcVE = value.getValueExpression(ctx,
Object.class);
- ValueExpression ve = getVarExpression(ctx, srcVE, itContext);
+ ValueExpression ve = getVarExpression(ctx, srcVE/*, itContext*/);
vm.setVariable(itContext._itemId, ve);
}
}
@@ -365,7 +451,8 @@
* Removes page attributes that we have exposed and, if applicable, restores
* them to their prior values (and scopes).
*/
- private void unExposeVariables(FaceletContext ctx, IterationContext itContext) {
+ private void unExposeVariables(FaceletContext ctx/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
VariableMapper vm = ctx.getVariableMapper();
// "nested" variables are now simply removed
if (itContext._itemId != null) {
@@ -385,7 +472,8 @@
* @return
*/
private ValueExpression getVarExpression(FaceletContext ctx,
- ValueExpression expr, IterationContext itContext) {
+ ValueExpression expr/*, IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
Object o = expr.getValue(ctx.getFacesContext().getELContext());
int k = itContext._index;
if (o.getClass().isArray() || o instanceof List) {
@@ -408,7 +496,8 @@
/**
* Release iteration variables
*/
- private void release(IterationContext itContext) {
+ private void release(/*IterationContext itContext*/) {
+ IterationContext itContext = getIterationContext();
itContext.items = null;
itContext._index = 0;
}
Modified: trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsTag.java
===================================================================
--- trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsTag.java 2008-10-07
09:29:25 UTC (rev 10679)
+++ trunk/ui/columns/src/main/java/org/richfaces/taglib/ColumnsTag.java 2008-10-07
14:31:22 UTC (rev 10680)
@@ -28,10 +28,13 @@
import org.richfaces.component.UIColumn;
import org.richfaces.component.html.HtmlColumn;
+import org.richfaces.el.ELBuilder;
import org.richfaces.iterator.ForEachIterator;
import org.richfaces.iterator.SimpleForEachIterator;
import org.richfaces.renderkit.CellRenderer;
+import sun.security.provider.certpath.Builder;
+
@SuppressWarnings("unused")
public class ColumnsTag extends UIComponentClassicTagBase implements
IterationTag {
@@ -338,7 +341,7 @@
@Override
protected void setProperties(UIComponent component) {
ELContext elContext = getContext(pageContext.getELContext());
-
+ String varReplacement = ELBuilder.trimEL(this.__value.getExpressionString()) +
"[" + index + "]";
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
try {
@@ -347,9 +350,23 @@
String fieldName = field.getName();
if (fieldName != null && fieldName.startsWith("_")) {
String attributeName = fieldName.replace("_", "");
- ValueExpression ex = (ValueExpression) o;
- ex = createValueExpression(elContext, ex);
- component.setValueExpression(attributeName, ex);
+ if (ColumnsHandler.filterAttributes.indexOf(attributeName) == -1 &&
+ ColumnsHandler.sortAttributes.indexOf(attributeName) == -1) {
+ ValueExpression ex = (ValueExpression) o;
+ ex = createValueExpression(elContext, ex);
+ component.setValueExpression(attributeName, ex);
+ } else {
+ ValueExpression ex = (ValueExpression) o;
+ ValueExpression expr = null;
+ if (!ex.isLiteralText()) {
+ expr = ELBuilder.createValueExpression(ex.getExpressionString(),
ex.getExpectedType(),
+ getFacesContext().getApplication().getExpressionFactory(),
pageContext.getELContext(), itemId, indexId,
+ varReplacement, String.valueOf(index));
+ }else {
+ expr = ex;
+ }
+ component.setValueExpression(attributeName, expr);
+ }
}
}
@@ -368,12 +385,10 @@
}
// Set SortExpression attribute especially for scrollable data table
if (_sortExpression != null) {
- //((HtmlColumn) component).setSortExpression(createSortExpression());
- String ex = createSortExpression();
- ValueExpression vexpr = getFacesContext().getApplication()
- .getExpressionFactory().createValueExpression(pageContext.getELContext(),
- ex, _sortExpression.getExpectedType());
- component.setValueExpression("sortExpression", vexpr);
+ ValueExpression expr =
ELBuilder.createValueExpression(_sortExpression.getExpressionString(),
_sortExpression.getExpectedType(),
+ getFacesContext().getApplication().getExpressionFactory(),
pageContext.getELContext(), itemId, indexId,
+ varReplacement, String.valueOf(index));
+ component.setValueExpression("sortExpression", expr);
}
Added: trunk/ui/columns/src/test/java/org/richfaces/el/ELBuilderTest.java
===================================================================
--- trunk/ui/columns/src/test/java/org/richfaces/el/ELBuilderTest.java
(rev 0)
+++ trunk/ui/columns/src/test/java/org/richfaces/el/ELBuilderTest.java 2008-10-07 14:31:22
UTC (rev 10680)
@@ -0,0 +1,83 @@
+/*
+ * ELBuilderTest.java Date created: 07.10.2008
+ * Last modified by: $Author$
+ * $Revision$ $Date$
+ */
+
+package org.richfaces.el;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.cglib.beans.BulkBean;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+/**
+ * JUnit test class for ElBuilder
+ * @author Andrey
+ *
+ */
+public class ELBuilderTest extends TestCase {
+
+ List<String> origList = null;
+
+ List<String> resultList = null;
+
+ String var;
+
+ String index;
+
+ String varR;
+
+ String indexR;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ var = "column";
+ index = "index";
+ varR = "bean.columns[0]";
+ indexR = "1";
+
+ origList = new ArrayList<String>();
+ origList.add("#{column.header}");
+ origList.add("#{var[index]}");
+ origList.add("#{bean.filterValue[index]}");
+ origList.add("#{column.index == 'column.index'}");
+ origList.add("#{var.column.index == 1}");
+ origList.add("#{index + 11 == 12}");
+ origList.add("#{var[index*2].index == column[index].index}");
+
+ resultList = new ArrayList<String>();
+ resultList.add("#{bean.columns[0].header}");
+ resultList.add("#{var[1]}");
+ resultList.add("#{bean.filterValue[1]}");
+ resultList.add("#{bean.columns[0].index == 'column.index'}");
+ resultList.add("#{var.column.index == 1}");
+ resultList.add("#{1 + 11 == 12}");
+ resultList.add("#{var[1*2].index == bean.columns[0][1].index}");
+ }
+
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testELBuilder() {
+ for (int i=0; i < origList.size(); i++) {
+ String o = origList.get(i);
+ ELBuilder builder = new ELBuilder(o, var, index, varR, indexR);
+ String r = null;
+ try {
+ r = builder.parse();
+ }catch (Exception e) {
+ System.out.println(e);
+ Assert.fail(e.getMessage());
+ }
+ Assert.assertEquals("ValueExpression was parsed incorrectly: " + o, r,
resultList.get(i));
+ }
+ }
+
+
+
+}