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.parser;
    17
    18  import org.apache.commons.jexl.JexlContext;
    19
    20  /***
    21   * reference - any variable expression.
    22   *
    23   * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
    24   * @version $Id: ASTReference.java 398272 2006-04-30 03:14:01Z dion $
    25   */
    26  public class ASTReference extends SimpleNode {
    27      /*** first variable in the expression. */
    28      protected SimpleNode root;
    29
    30      /***
    31       * Create the node given an id.
    32       *
    33       * @param id node id.
    34       */
    35      public ASTReference(int id) {
    36          super(id);
    37      }
    38
    39      /***
    40       * Create a node with the given parser and id.
    41       *
    42       * @param p a parser.
    43       * @param id node id.
    44       */
    45      public ASTReference(Parser p, int id) {
    46          super(p, id);
    47      }
    48
    49      /*** {@inheritDoc} */
    50      public Object jjtAccept(ParserVisitor visitor, Object data) {
    51          return visitor.visit(this, data);
    52      }
    53
    54      /*** {@inheritDoc} */
    55      public Object value(JexlContext jc) throws Exception {
    56          return execute(null, jc);
    57      }
    58
    59      /*** Store the first child as {@link ASTReference#root root}. */
    60      public void jjtClose() {
    61          root = (SimpleNode) jjtGetChild(0);
    62      }
    63
    64      /***
    65       * evaluate each piece of the reference.
    66       *
    67       * e.g. foo.bar.woogie[2].name, foo is our 'root', and we need to
    68       * evaluate 'bar.woogie[2].name' relative to foo.
    69       *
    70       * @param jc the {@link JexlContext} to evaluate against.
    71       * @param obj not used. root.value(jc) is used instead.
    72       * @return the value of the array expression.
    73       * @throws Exception on any error
    74       */
    75      public Object execute(Object obj, JexlContext jc) throws Exception {
    76          Object o = root.value(jc);
    77
    78          /*
    79           * ignore the first child - it's our identifier
    80           */
    81          for (int i = 1; i < jjtGetNumChildren(); i++) {
    82              o = ((SimpleNode) jjtGetChild(i)).execute(o, jc);
    83
    84              // check for a variable in the context named
    85              // child0.child1.child2 etc
    86              if (o == null) {
    87                  String varName = getIdentifierToDepth(i);
    88                  o = jc.getVars().get(varName);
    89              }
    90          }
    91
    92          return o;
    93      }
    94
    95      /***
    96       * This method returns a variable from this identifier and it's children.
    97       * For an expression like 'a.b.c', a is child zero, b is child 1 and c is
    98       * child 2.
    99       *
    100      * @param i the depth of the child nodes to go to
    101      * @return the a dotted variable from this identifier and it's child nodes.
    102      */
    103     private String getIdentifierToDepth(int i) {
    104         StringBuffer varName = new StringBuffer();
    105         for (int j = 0; j <= i; j++) {
    106             SimpleNode node = (SimpleNode) jjtGetChild(j);
    107             if (node instanceof ASTIdentifier) {
    108                 varName.append(((ASTIdentifier) node).getIdentifierString());
    109                 if (j != i) {
    110                     varName.append('.');
    111                 }
    112             }
    113         }
    114         return varName.toString();
    115     }
    116
    117     /***
    118      * Gets the variable name of {@link ASTReference#root root}.
    119      * @return the identifier.
    120      * @throws Exception on any error
    121      * @see ASTIdentifier#getIdentifierString()
    122      * @see ASTArrayAccess#getIdentifierString()
    123      */
    124     public String getRootString() throws Exception {
    125         if (root instanceof ASTIdentifier) {
    126             return ((ASTIdentifier) root).getIdentifierString();
    127         }
    128
    129         if (root instanceof ASTArrayAccess) {
    130             return ((ASTArrayAccess) root).getIdentifierString();
    131         }
    132
    133         throw new Exception("programmer error : ASTReference : root not known" + root);
    134     }
    135 }