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 }