/*
* Copyright 2002,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jexl.parser;
import org.apache.commons.jexl.JexlContext;
import org.apache.commons.jexl.util.Coercion;
import org.apache.commons.jexl.util.Introspector;
import org.apache.commons.jexl.util.introspection.Info;
import org.apache.commons.jexl.util.introspection.VelPropertyGet;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Array;
/**
* Like an ASTIdentifier, but with array access allowed
*
* $foo[2]
*
* @author <a href="mailto:geirm@apache.org">Geir Magnusson Jr.</a>
* @version $Id: ASTArrayAccess.java,v 1.7 2004/08/22 07:42:35 dion Exp $
*/
public class ASTArrayAccess extends SimpleNode
{
/** dummy velocity info */
private static Info DUMMY = new Info("", 1, 1);
public ASTArrayAccess(int id)
{
super(id);
}
public ASTArrayAccess(Parser p, int id)
{
super(p, id);
}
/** Accept the visitor. **/
public Object jjtAccept(ParserVisitor visitor, Object data)
{
return visitor.visit(this, data);
}
/*
* evaluate array access upon a base object
*
* foo.bar[2]
*
* makes me rethink the array operator :)
*/
public Object execute(Object obj, JexlContext jc)
throws Exception
{
ASTIdentifier base = (ASTIdentifier) jjtGetChild(0);
obj = base.execute(obj,jc);
/*
* ignore the first child - it's our identifier
*/
for(int i=1; i<jjtGetNumChildren(); i++)
{
Object loc = ((SimpleNode) jjtGetChild(i)).value(jc);
if(loc==null)
return null;
obj = evaluateExpr(obj, loc);
}
return obj;
}
/**
* return the value of this node
*/
public Object value(JexlContext jc)
throws Exception
{
/*
* get the base ASTIdentifier
*/
ASTIdentifier base = (ASTIdentifier) jjtGetChild(0);
Object o = base.value(jc);
/*
* ignore the first child - it's our identifier
*/
for(int i=1; i<jjtGetNumChildren(); i++)
{
Object loc = ((SimpleNode) jjtGetChild(i)).value(jc);
if(loc==null)
return null;
o = evaluateExpr(o, loc);
}
return o;
}
public static Object evaluateExpr(Object o, Object loc)
throws Exception
{
/*
* following the JSTL EL rules
*/
if (o == null)
return null;
if (loc == null)
return null;
if (o instanceof Map)
{
if (!((Map)o).containsKey(loc))
return null;
return ((Map)o).get(loc);
}
else if (o instanceof List)
{
int idx = Coercion.coerceInteger(loc).intValue();
try
{
return ((List)o).get(idx);
}
catch(IndexOutOfBoundsException iobe)
{
return null;
}
}
else if (o.getClass().isArray())
{
int idx = Coercion.coerceInteger(loc).intValue();
try
{
return Array.get(o, idx);
}
catch(ArrayIndexOutOfBoundsException aiobe)
{
return null;
}
}
else
{
/*
* "Otherwise (a JavaBean object)..." huh? :)
*/
String s = loc.toString();
VelPropertyGet vg = Introspector.getUberspect().getPropertyGet(o, s, DUMMY);
if (vg != null)
{
return vg.invoke(o);
}
}
throw new Exception("Unsupported object type for array [] accessor");
}
public String getIdentifierString()
{
return ((ASTIdentifier) jjtGetChild(0)).getIdentifierString();
}
}