📄 astreference.java
字号:
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.io.IOException;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import org.apache.velocity.app.event.EventHandlerUtil;
import org.apache.velocity.context.Context;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.parser.Parser;
import org.apache.velocity.runtime.parser.ParserVisitor;
import org.apache.velocity.runtime.parser.Token;
import org.apache.velocity.util.introspection.Info;
import org.apache.velocity.util.introspection.VelPropertySet;
/**
* This class is responsible for handling the references in
* VTL ($foo).
*
* Please look at the Parser.jjt file which is
* what controls the generation of this class.
*
* @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
* @author <a href="mailto:geirm@optonline.net">Geir Magnusson Jr.</a>
* @author <a href="mailto:Christoph.Reck@dlr.de">Christoph Reck</a>
* @author <a href="mailto:kjohnson@transparent.com>Kent Johnson</a>
* @version $Id: ASTReference.java 471381 2006-11-05 08:56:58Z wglass $
*/
public class ASTReference extends SimpleNode
{
/* Reference types */
private static final int NORMAL_REFERENCE = 1;
private static final int FORMAL_REFERENCE = 2;
private static final int QUIET_REFERENCE = 3;
private static final int RUNT = 4;
private int referenceType;
private String nullString;
private String rootString;
private boolean escaped = false;
private boolean computableReference = true;
private boolean logOnNull = true;
private String escPrefix = "";
private String morePrefix = "";
private String identifier = "";
private String literal = null;
private int numChildren = 0;
protected Info uberInfo;
/**
* @param id
*/
public ASTReference(int id)
{
super(id);
}
/**
* @param p
* @param id
*/
public ASTReference(Parser p, int id)
{
super(p, id);
}
/**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#jjtAccept(org.apache.velocity.runtime.parser.ParserVisitor, java.lang.Object)
*/
public Object jjtAccept(ParserVisitor visitor, Object data)
{
return visitor.visit(this, data);
}
/**
* @see org.apache.velocity.runtime.parser.node.SimpleNode#init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)
*/
public Object init(InternalContextAdapter context, Object data)
throws TemplateInitException
{
/*
* init our children
*/
super.init(context, data);
/*
* the only thing we can do in init() is getRoot()
* as that is template based, not context based,
* so it's thread- and context-safe
*/
rootString = getRoot();
numChildren = jjtGetNumChildren();
/*
* and if appropriate...
*/
if (numChildren > 0 )
{
identifier = jjtGetChild(numChildren - 1).getFirstToken().image;
}
/*
* make an uberinfo - saves new's later on
*/
uberInfo = new Info(context.getCurrentTemplateName(),
getLine(),getColumn());
/*
* track whether we log invalid references
*/
logOnNull =
rsvc.getBoolean(RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, true);
return data;
}
/**
* Returns the 'root string', the reference key
* @return the root string.
*/
public String getRootString()
{
return rootString;
}
/**
* gets an Object that 'is' the value of the reference
*
* @param o unused Object parameter
* @param context context used to generate value
* @return The execution result.
* @throws MethodInvocationException
*/
public Object execute(Object o, InternalContextAdapter context)
throws MethodInvocationException
{
if (referenceType == RUNT)
return null;
/*
* get the root object from the context
*/
Object result = getVariableValue(context, rootString);
if (result == null)
{
return EventHandlerUtil.invalidGetMethod(rsvc, context,
"$" + rootString, null, null, uberInfo);
}
/*
* Iteratively work 'down' (it's flat...) the reference
* to get the value, but check to make sure that
* every result along the path is valid. For example:
*
* $hashtable.Customer.Name
*
* The $hashtable may be valid, but there is no key
* 'Customer' in the hashtable so we want to stop
* when we find a null value and return the null
* so the error gets logged.
*/
try
{
Object previousResult = result;
int failedChild = -1;
for (int i = 0; i < numChildren; i++)
{
previousResult = result;
result = jjtGetChild(i).execute(result,context);
if (result == null)
{
failedChild = i;
break;
}
}
if (result == null)
{
if (failedChild == -1)
{
result = EventHandlerUtil.invalidGetMethod(rsvc, context,
"$" + rootString, previousResult, null, uberInfo);
}
else
{
StringBuffer name = new StringBuffer("$").append(rootString);
for (int i = 0; i <= failedChild; i++)
{
Node node = jjtGetChild(i);
if (node instanceof ASTMethod)
{
name.append(".").append(((ASTMethod) node).getMethodName()).append("()");
}
else
{
name.append(".").append(node.getFirstToken().image);
}
}
if (jjtGetChild(failedChild) instanceof ASTMethod)
{
String methodName = ((ASTMethod) jjtGetChild(failedChild)).getMethodName();
result = EventHandlerUtil.invalidMethod(rsvc, context,
name.toString(), previousResult, methodName, uberInfo);
}
else
{
String property = jjtGetChild(failedChild).getFirstToken().image;
result = EventHandlerUtil.invalidGetMethod(rsvc, context,
name.toString(), previousResult, property, uberInfo);
}
}
}
return result;
}
catch(MethodInvocationException mie)
{
/*
* someone tossed their cookies
*/
log.error("Method " + mie.getMethodName()
+ " threw exception for reference $"
+ rootString
+ " in template " + context.getCurrentTemplateName()
+ " at " + " [" + this.getLine() + ","
+ this.getColumn() + "]");
mie.setReferenceName(rootString);
throw mie;
}
}
/**
* gets the value of the reference and outputs it to the
* writer.
*
* @param context context of data to use in getting value
* @param writer writer to render to
* @return True if rendering was successful.
* @throws IOException
* @throws MethodInvocationException
*/
public boolean render(InternalContextAdapter context, Writer writer)
throws IOException, MethodInvocationException
{
if (referenceType == RUNT)
{
if (context.getAllowRendering())
{
writer.write(rootString);
}
return true;
}
Object value = execute(null, context);
/*
* if this reference is escaped (\$foo) then we want to do one of two things :
* 1) if this is a reference in the context, then we want to print $foo
* 2) if not, then \$foo (its considered schmoo, not VTL)
*/
if (escaped)
{
if (value == null)
{
if (context.getAllowRendering())
{
writer.write(escPrefix);
writer.write("\\");
writer.write(nullString);
}
}
else
{
if (context.getAllowRendering())
{
writer.write(escPrefix);
writer.write(nullString);
}
}
return true;
}
/*
* the normal processing
*
* if we have an event cartridge, get a new value object
*/
value = EventHandlerUtil.referenceInsert(rsvc, context, literal(), value);
String toString = null;
if (value != null)
{
toString = value.toString();
}
/*
* if value is null...
*/
if ( value == null || toString == null)
{
/*
* write prefix twice, because it's schmoo, so the \ don't escape each other...
*/
if (context.getAllowRendering())
{
writer.write(escPrefix);
writer.write(escPrefix);
writer.write(morePrefix);
writer.write(nullString);
}
if (logOnNull && referenceType != QUIET_REFERENCE && log.isInfoEnabled())
{
log.info("Null reference [template '"
+ context.getCurrentTemplateName() + "', line "
+ this.getLine() + ", column " + this.getColumn()
+ "] : " + this.literal() + " cannot be resolved.");
}
return true;
}
else
{
/*
* non-null processing
*/
if (context.getAllowRendering())
{
writer.write(escPrefix);
writer.write(morePrefix);
writer.write(toString);
}
return true;
}
}
/**
* Computes boolean value of this reference
* Returns the actual value of reference return type
* boolean, and 'true' if value is not null
*
* @param context context to compute value with
* @return True if evaluation was ok.
* @throws MethodInvocationException
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -