1. /*
  2. * Copyright 2002,2004 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. import java.io.StringReader;
  18. import org.apache.commons.jexl.parser.ASTExpressionExpression;
  19. import org.apache.commons.jexl.parser.ASTReferenceExpression;
  20. import org.apache.commons.jexl.parser.Parser;
  21. import org.apache.commons.jexl.parser.SimpleNode;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. /**
  25. * <p>
  26. * Creates Expression objects. To create a JEXL Expression object, pass
  27. * valid JEXL syntax to the static createExpression() method:
  28. * </p>
  29. *
  30. * <pre>
  31. * String jexl = "array[1]";
  32. * Expression expression = ExpressionFactory.createExpression( jexl );
  33. * </pre>
  34. *
  35. * <p>
  36. * When an {@link Expression} object is created, the JEXL syntax is
  37. * parsed and verified. If the supplied expression is neither an
  38. * expression not a reference, an exception is thrown from createException().
  39. * </p>
  40. * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
  41. * @version $Id: ExpressionFactory.java,v 1.7 2004/08/23 13:50:00 dion Exp $
  42. */
  43. public class ExpressionFactory
  44. {
  45. /**
  46. * The Log to which all ExpressionFactory messages will be logged.
  47. */
  48. protected static Log log =
  49. LogFactory.getLog("org.apache.commons.jexl.ExpressionFactory");
  50. /**
  51. * The singleton ExpressionFactory also holds a single instance of {@link Parser}.
  52. * When parsing expressions, ExpressionFactory synchronizes on Parser.
  53. */
  54. protected static Parser parser = new Parser(new StringReader(";")); //$NON-NLS-1$
  55. /**
  56. * ExpressionFactory is a single and this is the private
  57. * status instance fufilling that pattern.
  58. */
  59. protected static ExpressionFactory ef = new ExpressionFactory();
  60. /**
  61. * Private constructor, the single instance is always obtained
  62. * with a call to getInstance().
  63. */
  64. private ExpressionFactory(){}
  65. /**
  66. * Returns the single instance of ExpressionFactory.
  67. * @return the instance of ExpressionFactory.
  68. */
  69. protected static ExpressionFactory getInstance()
  70. {
  71. return ef;
  72. }
  73. /**
  74. * Creates an Expression from a String containing valid
  75. * JEXL syntax. This method parses the expression which
  76. * must contain either a reference or an expression.
  77. * @param expression A String containing valid JEXL syntax
  78. * @return An Expression object which can be evaluated with a JexlContext
  79. * @throws Exception An exception can be thrown if there is a problem parsing
  80. * his expression, or if the expression is neither an
  81. * expression or a reference.
  82. */
  83. public static Expression createExpression(String expression)
  84. throws Exception
  85. {
  86. return getInstance().createNewExpression(expression);
  87. }
  88. /**
  89. * Creates a new Expression based on the expression string.
  90. *
  91. * @param expression valid Jexl expression
  92. * @return Expression
  93. * @throws Exception for a variety of reasons - mostly malformed
  94. * Jexl expression
  95. */
  96. protected Expression createNewExpression(String expression)
  97. throws Exception {
  98. String expr = cleanExpression(expression);
  99. // Parse the Expression
  100. SimpleNode tree;
  101. synchronized(parser)
  102. {
  103. log.debug( "Parsing expression: " + expr );
  104. tree = parser.parse(new StringReader(expr));
  105. }
  106. // Must be a simple reference or expression, otherwise
  107. // throw an exception.
  108. SimpleNode node = (SimpleNode) tree.jjtGetChild(0);
  109. if( (node instanceof ASTReferenceExpression) ||
  110. (node instanceof ASTExpressionExpression) )
  111. {
  112. node = (SimpleNode) node.jjtGetChild(0);
  113. Expression e = new ExpressionImpl(expression, node);
  114. return e;
  115. }
  116. else
  117. {
  118. log.error( "Invalid Expression, node of type: " + node.getClass().getName() );
  119. throw new Exception("Invalid Expression: neither Reference nor Expression");
  120. }
  121. }
  122. /**
  123. * Trims the expression and adds a semi-colon if missing.
  124. * @param expression to clean
  125. * @return trimmed expression ending in a semi-colon
  126. */
  127. private String cleanExpression(String expression) {
  128. String expr = expression.trim();
  129. if (!expr.endsWith(";"))
  130. {
  131. expr += ";";
  132. }
  133. return expr;
  134. }
  135. }