org.apache.velocity.runtime.parser.node.ASTMethod Maven / Gradle / Ivy
package org.apache.velocity.runtime.parser.node;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.app.event.EventHandlerUtil;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.parser.Parser;
import org.apache.velocity.util.introspection.Info;
import org.apache.velocity.util.introspection.IntrospectionCacheData;
import org.apache.velocity.util.introspection.VelMethod;
/**
* ASTMethod.java
*
* Method support for references : $foo.method()
*
* NOTE :
*
* introspection is now done at render time.
*
* Please look at the Parser.jjt file which is
* what controls the generation of this class.
*
* @author Jason van Zyl
* @author Geir Magnusson Jr.
* @version $Id: ASTMethod.java 720228 2008-11-24 16:58:33Z nbubna $
*/
public class ASTMethod extends SimpleNode
{
private String methodName = "";
private int paramCount = 0;
protected Info uberInfo;
/**
* Indicates if we are running in strict reference mode.
*/
protected boolean strictRef = false;
/**
* @param id
*/
public ASTMethod(int id)
{
super(id);
}
/**
* @param p
* @param id
*/
public ASTMethod(Parser p, int id)
{
super(p, id);
}
/**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object)
*/
public Object jjtAccept(ParserVisitor visitor, Object data)
{
return visitor.visit(this, data);
}
/**
* simple init - init our subtree and get what we can from
* the AST
* @param context
* @param data
* @return The init result
* @throws TemplateInitException
*/
public Object init( InternalContextAdapter context, Object data)
throws TemplateInitException
{
super.init( context, data );
/*
* make an uberinfo - saves new's later on
*/
uberInfo = new Info(getTemplateName(),
getLine(),getColumn());
/*
* this is about all we can do
*/
methodName = getFirstToken().image;
paramCount = jjtGetNumChildren() - 1;
strictRef = rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false);
return data;
}
/**
* invokes the method. Returns null if a problem, the
* actual return if the method returns something, or
* an empty string "" if the method returns void
* @param o
* @param context
* @return Result or null.
* @throws MethodInvocationException
*/
public Object execute(Object o, InternalContextAdapter context)
throws MethodInvocationException
{
/*
* new strategy (strategery!) for introspection. Since we want
* to be thread- as well as context-safe, we *must* do it now,
* at execution time. There can be no in-node caching,
* but if we are careful, we can do it in the context.
*/
VelMethod method = null;
Object [] params = new Object[paramCount];
try
{
/*
* sadly, we do need recalc the values of the args, as this can
* change from visit to visit
*/
final Class[] paramClasses = paramCount > 0 ? new Class[paramCount] : ArrayUtils.EMPTY_CLASS_ARRAY;
for (int j = 0; j < paramCount; j++)
{
params[j] = jjtGetChild(j + 1).value(context);
if (params[j] != null)
{
paramClasses[j] = params[j].getClass();
}
}
/*
* check the cache
*/
MethodCacheKey mck = new MethodCacheKey(methodName, paramClasses);
IntrospectionCacheData icd = context.icacheGet( mck );
/*
* like ASTIdentifier, if we have cache information, and the
* Class of Object o is the same as that in the cache, we are
* safe.
*/
if ( icd != null && (o != null && icd.contextData == o.getClass()) )
{
/*
* get the method from the cache
*/
method = (VelMethod) icd.thingy;
}
else
{
/*
* otherwise, do the introspection, and then
* cache it
*/
method = rsvc.getUberspect().getMethod(o, methodName, params, new Info(getTemplateName(), getLine(), getColumn()));
if ((method != null) && (o != null))
{
icd = new IntrospectionCacheData();
icd.contextData = o.getClass();
icd.thingy = method;
context.icachePut( mck, icd );
}
}
/*
* if we still haven't gotten the method, either we are calling
* a method that doesn't exist (which is fine...) or I screwed
* it up.
*/
if (method == null)
{
if (strictRef)
{
// Create a parameter list for the exception error message
StringBuffer plist = new StringBuffer();
for (int i=0; i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy