net.sf.jxls.reader.ExpressionCollectionParser Maven / Gradle / Ivy
package net.sf.jxls.reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.parser.ASTIdentifier;
import org.apache.commons.jexl2.parser.ASTReference;
import org.apache.commons.jexl2.parser.Node;
import org.apache.commons.jexl2.parser.Parser;
import org.apache.commons.jexl2.parser.SimpleNode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ExpressionCollectionParser {
protected final Log log = LogFactory.getLog(getClass());
public final static String COLLECTION_REFERENCE_SUFFIX = "_JxLsC_";
// This is set up as a ThreadLocal parser to avoid threading issues.
private static ThreadLocal parser = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Parser(new StringReader(";"));
}
};
private boolean jexlInnerCollectionsAccess;
private String collectionExpression;
private Collection collection;
public ExpressionCollectionParser(JexlContext jexlContext, String expr, boolean jexlInnerCollectionsAccess) {
try {
this.jexlInnerCollectionsAccess = jexlInnerCollectionsAccess;
SimpleNode tree = ((Parser) parser.get()).parse(new StringReader(expr), null);
ArrayList references = new ArrayList();
findReferences(references, tree);
findCollection(jexlContext, references);
} catch (Exception e) {
log.error("Can't parse jexl expression " + expr);
throw new RuntimeException("Can't parse jexl expression", e);
}
}
public String getCollectionExpression() {
return collectionExpression;
}
public Collection getCollection() {
return collection;
}
private void findReferences(List references, Node node) {
if (node instanceof ASTReference) {
references.add(node);
}
int childCount = node.jjtGetNumChildren();
for (int i = 0; i < childCount; i++) {
findReferences(references, node.jjtGetChild(i));
}
}
private void findCollection(JexlContext jexlContext, List references) {
Node node;
for (Iterator itr = references.iterator(); itr.hasNext();) {
node = (Node) itr.next();
String expression = findCollectionProperties(jexlContext, node);
if (expression != null) {
if (!expression.endsWith(ExpressionCollectionParser.COLLECTION_REFERENCE_SUFFIX)) {
collectionExpression = expression;
}
break;
}
}
}
private String findCollectionProperties(JexlContext jexlContext, Node node) {
int childCount = node.jjtGetNumChildren();
Node child;
String subExpr = null;
JexlEngine jexlEngine = new JexlEngine();
for (int i = 0; i < childCount; i++) {
child = node.jjtGetChild(i);
if (child instanceof ASTIdentifier) {
ASTIdentifier ident = (ASTIdentifier) child;
if (subExpr == null) {
subExpr = ident.image;
} else {
subExpr = subExpr + "." + ident.image;
}
if (jexlInnerCollectionsAccess) {
if (subExpr.endsWith(ExpressionCollectionParser.COLLECTION_REFERENCE_SUFFIX)) {
return subExpr;
}
}
try {
Expression e = jexlEngine.createExpression(subExpr);
Object obj = e.evaluate(jexlContext);
if (obj instanceof Collection) {
this.collection = (Collection) obj;
return subExpr;
}
} catch (Exception e) {
// TODO: insert proper logging here
return null;
}
}
}
return null;
}
}