View Javadoc

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  
17  package org.apache.commons.jexl.parser;
18  
19  import org.apache.commons.jexl.JexlContext;
20  import org.apache.commons.jexl.util.Coercion;
21  import org.apache.commons.jexl.util.Introspector;
22  import org.apache.commons.jexl.util.introspection.Info;
23  import org.apache.commons.jexl.util.introspection.VelPropertyGet;
24  
25  import java.util.List;
26  import java.util.Map;
27  import java.lang.reflect.Array;
28  
29  
30  /***
31   *  Like an ASTIdentifier, but with array access allowed
32   *
33   *    $foo[2]
34   *
35   *  @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
36   *  @version $Id: ASTArrayAccess.java,v 1.7 2004/08/22 07:42:35 dion Exp $
37   */
38  public class ASTArrayAccess extends SimpleNode
39  {
40      /*** dummy velocity info */
41      private static Info DUMMY = new Info("", 1, 1);
42      
43      public ASTArrayAccess(int id)
44      {
45          super(id);
46      }
47  
48      public ASTArrayAccess(Parser p, int id)
49      {
50          super(p, id);
51      }
52  
53  
54      /*** Accept the visitor. **/
55      public Object jjtAccept(ParserVisitor visitor, Object data)
56      {
57          return visitor.visit(this, data);
58      }
59  
60      /*
61       * evaluate array access upon a base object
62       *
63       *   foo.bar[2]
64       *
65       *  makes me rethink the array operator :)
66       */
67      public Object execute(Object obj, JexlContext jc)
68               throws Exception
69       {
70           ASTIdentifier base = (ASTIdentifier) jjtGetChild(0);
71  
72           obj = base.execute(obj,jc);
73  
74           /*
75            * ignore the first child - it's our identifier
76            */
77           for(int i=1; i<jjtGetNumChildren(); i++)
78           {
79               Object loc = ((SimpleNode) jjtGetChild(i)).value(jc);
80  
81               if(loc==null)
82                   return null;
83  
84               obj = evaluateExpr(obj, loc);
85           }
86  
87           return obj;
88       }
89  
90      /***
91       *  return the value of this node
92       */
93      public Object value(JexlContext jc)
94          throws Exception
95      {
96          /*
97           * get the base ASTIdentifier
98           */
99  
100         ASTIdentifier base = (ASTIdentifier) jjtGetChild(0);
101 
102         Object o = base.value(jc);
103 
104         /*
105          * ignore the first child - it's our identifier
106          */
107         for(int i=1; i<jjtGetNumChildren(); i++)
108         {
109             Object loc = ((SimpleNode) jjtGetChild(i)).value(jc);
110 
111             if(loc==null)
112                 return null;
113 
114             o = evaluateExpr(o, loc);
115         }
116 
117         return o;
118     }
119 
120     public static Object evaluateExpr(Object o, Object loc)
121         throws Exception
122     {
123         /*
124          * following the JSTL EL rules
125          */
126 
127         if (o == null)
128             return null;
129 
130         if (loc == null)
131             return null;
132 
133         if (o instanceof Map)
134         {
135             if (!((Map)o).containsKey(loc))
136                 return null;
137 
138             return ((Map)o).get(loc);
139         }
140         else if (o instanceof List)
141         {
142             int idx = Coercion.coerceInteger(loc).intValue();
143 
144             try
145             {
146                 return ((List)o).get(idx);
147             }
148             catch(IndexOutOfBoundsException iobe)
149             {
150                 return null;
151             }
152         }
153         else if (o.getClass().isArray())
154         {
155             int idx = Coercion.coerceInteger(loc).intValue();
156 
157             try
158             {
159                 return Array.get(o, idx);
160             }
161             catch(ArrayIndexOutOfBoundsException aiobe)
162             {
163                 return null;
164             }
165         }
166         else
167         {
168             /*
169              *  "Otherwise (a JavaBean object)..."  huh? :)
170              */
171 
172             String s = loc.toString();
173 
174             VelPropertyGet vg = Introspector.getUberspect().getPropertyGet(o, s, DUMMY);
175 
176             if (vg != null)
177             {
178                 return vg.invoke(o);
179             }
180         }
181 
182         throw new Exception("Unsupported object type for array [] accessor");
183     }
184 
185     public String getIdentifierString()
186     {
187         return ((ASTIdentifier) jjtGetChild(0)).getIdentifierString();
188     }
189 }