1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jexl;
17
18 import java.io.StringReader;
19
20 import org.apache.commons.jexl.parser.ASTExpressionExpression;
21 import org.apache.commons.jexl.parser.ASTForeachStatement;
22 import org.apache.commons.jexl.parser.ASTIfStatement;
23 import org.apache.commons.jexl.parser.ASTReferenceExpression;
24 import org.apache.commons.jexl.parser.ASTStatementExpression;
25 import org.apache.commons.jexl.parser.ASTWhileStatement;
26 import org.apache.commons.jexl.parser.ParseException;
27 import org.apache.commons.jexl.parser.Parser;
28 import org.apache.commons.jexl.parser.SimpleNode;
29 import org.apache.commons.jexl.parser.TokenMgrError;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33 /***
34 * <p>
35 * Creates Expression objects. To create a JEXL Expression object, pass
36 * valid JEXL syntax to the static createExpression() method:
37 * </p>
38 *
39 * <pre>
40 * String jexl = "array[1]";
41 * Expression expression = ExpressionFactory.createExpression( jexl );
42 * </pre>
43 *
44 * <p>
45 * When an {@link Expression} object is created, the JEXL syntax is
46 * parsed and verified. If the supplied expression is neither an
47 * expression nor a reference, an exception is thrown from createException().
48 * </p>
49 * @since 1.0
50 * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
51 * @version $Id: ExpressionFactory.java 429169 2006-08-06 18:36:29Z rahul $
52 */
53 public class ExpressionFactory {
54 /***
55 * The Log to which all ExpressionFactory messages will be logged.
56 */
57 protected static Log log =
58 LogFactory.getLog("org.apache.commons.jexl.ExpressionFactory");
59
60 /***
61 * The singleton ExpressionFactory also holds a single instance of
62 * {@link Parser}.
63 * When parsing expressions, ExpressionFactory synchronizes on Parser.
64 */
65 protected static Parser parser =
66 new Parser(new StringReader(";"));
67
68 /***
69 * ExpressionFactory is a singleton and this is the private
70 * instance fufilling that pattern.
71 */
72 protected static ExpressionFactory ef = new ExpressionFactory();
73
74 /***
75 * Private constructor, the single instance is always obtained
76 * with a call to getInstance().
77 */
78 private ExpressionFactory() {
79 }
80
81 /***
82 * Returns the single instance of ExpressionFactory.
83 * @return the instance of ExpressionFactory.
84 */
85 protected static ExpressionFactory getInstance() {
86 return ef;
87 }
88
89 /***
90 * Creates an Expression from a String containing valid
91 * JEXL syntax. This method parses the expression which
92 * must contain either a reference or an expression.
93 * @param expression A String containing valid JEXL syntax
94 * @return An Expression object which can be evaluated with a JexlContext
95 * @throws Exception An exception can be thrown if there is a problem
96 * parsing this expression, or if the expression is neither an
97 * expression or a reference.
98 */
99 public static Expression createExpression(String expression)
100 throws Exception {
101 return getInstance().createNewExpression(expression);
102 }
103
104
105 /***
106 * Creates a new Expression based on the expression string.
107 *
108 * @param expression valid Jexl expression
109 * @return Expression
110 * @throws Exception for a variety of reasons - mostly malformed
111 * Jexl expression
112 */
113 protected Expression createNewExpression(final String expression)
114 throws Exception {
115
116 String expr = cleanExpression(expression);
117
118
119 SimpleNode tree;
120 synchronized (parser) {
121 log.debug("Parsing expression: " + expr);
122 try {
123 tree = parser.parse(new StringReader(expr));
124 } catch (TokenMgrError tme) {
125 throw new ParseException(tme.getMessage());
126 }
127 }
128
129 if (tree.jjtGetNumChildren() > 1 && log.isWarnEnabled()) {
130 log.warn("The JEXL Expression created will be a reference"
131 + " to the first expression from the supplied script: \""
132 + expression + "\" ");
133 }
134
135
136
137 SimpleNode node = (SimpleNode) tree.jjtGetChild(0);
138
139
140 if (node instanceof ASTReferenceExpression
141 || node instanceof ASTExpressionExpression
142 || node instanceof ASTStatementExpression
143 || node instanceof ASTIfStatement
144 || node instanceof ASTWhileStatement
145 || node instanceof ASTForeachStatement
146 ) {
147 return new ExpressionImpl(expression, node);
148 }
149 log.error("Invalid Expression, node of type: "
150 + node.getClass().getName());
151 throw new Exception("Invalid Expression: not a Reference, Expression, "
152 + "Statement or If");
153 }
154
155 /***
156 * Trims the expression and adds a semi-colon if missing.
157 * @param expression to clean
158 * @return trimmed expression ending in a semi-colon
159 */
160 private String cleanExpression(String expression) {
161 String expr = expression.trim();
162 if (!expr.endsWith(";")) {
163 expr += ";";
164 }
165 return expr;
166 }
167 }