001: /*
002: * Copyright 2002-2006 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jexl.parser;
017:
018: import org.apache.commons.jexl.JexlContext;
019:
020: /**
021: * reference - any variable expression.
022: *
023: * @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
024: * @version $Id: ASTReference.java 398272 2006-04-30 03:14:01Z dion $
025: */
026: public class ASTReference extends SimpleNode {
027: /** first variable in the expression. */
028: protected SimpleNode root;
029:
030: /**
031: * Create the node given an id.
032: *
033: * @param id node id.
034: */
035: public ASTReference(int id) {
036: super (id);
037: }
038:
039: /**
040: * Create a node with the given parser and id.
041: *
042: * @param p a parser.
043: * @param id node id.
044: */
045: public ASTReference(Parser p, int id) {
046: super (p, id);
047: }
048:
049: /** {@inheritDoc} */
050: public Object jjtAccept(ParserVisitor visitor, Object data) {
051: return visitor.visit(this , data);
052: }
053:
054: /** {@inheritDoc} */
055: public Object value(JexlContext jc) throws Exception {
056: return execute(null, jc);
057: }
058:
059: /** Store the first child as {@link ASTReference#root root}. */
060: public void jjtClose() {
061: root = (SimpleNode) jjtGetChild(0);
062: }
063:
064: /**
065: * evaluate each piece of the reference.
066: *
067: * e.g. foo.bar.woogie[2].name, foo is our 'root', and we need to
068: * evaluate 'bar.woogie[2].name' relative to foo.
069: *
070: * @param jc the {@link JexlContext} to evaluate against.
071: * @param obj not used. root.value(jc) is used instead.
072: * @return the value of the array expression.
073: * @throws Exception on any error
074: */
075: public Object execute(Object obj, JexlContext jc) throws Exception {
076: Object o = root.value(jc);
077:
078: /*
079: * ignore the first child - it's our identifier
080: */
081: for (int i = 1; i < jjtGetNumChildren(); i++) {
082: o = ((SimpleNode) jjtGetChild(i)).execute(o, jc);
083:
084: // check for a variable in the context named
085: // child0.child1.child2 etc
086: if (o == null) {
087: String varName = getIdentifierToDepth(i);
088: o = jc.getVars().get(varName);
089: }
090: }
091:
092: return o;
093: }
094:
095: /**
096: * This method returns a variable from this identifier and it's children.
097: * For an expression like 'a.b.c', a is child zero, b is child 1 and c is
098: * child 2.
099: *
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)
109: .getIdentifierString());
110: if (j != i) {
111: varName.append('.');
112: }
113: }
114: }
115: return varName.toString();
116: }
117:
118: /**
119: * Gets the variable name of {@link ASTReference#root root}.
120: * @return the identifier.
121: * @throws Exception on any error
122: * @see ASTIdentifier#getIdentifierString()
123: * @see ASTArrayAccess#getIdentifierString()
124: */
125: public String getRootString() throws Exception {
126: if (root instanceof ASTIdentifier) {
127: return ((ASTIdentifier) root).getIdentifierString();
128: }
129:
130: if (root instanceof ASTArrayAccess) {
131: return ((ASTArrayAccess) root).getIdentifierString();
132: }
133:
134: throw new Exception(
135: "programmer error : ASTReference : root not known"
136: + root);
137: }
138: }
|