View Javadoc

    1   /*
    2    * Copyright 2002-2006 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    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(";")); //$NON-NLS-1$
    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         // Parse the Expression
    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         // Must be a simple reference, expression, statement or if, otherwise
    136         // throw an exception.
    137         SimpleNode node = (SimpleNode) tree.jjtGetChild(0);
    138
    139         // TODO: Can we get rid of these checks?
    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 }