org.apache.velocity.runtime.directive.Parse Maven / Gradle / Ivy
package org.apache.velocity.runtime.directive;
/*
* 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.util.List;
import java.util.ArrayList;
import org.apache.velocity.Template;
import org.apache.velocity.app.event.EventHandlerUtil;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.log.Log;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.parser.node.SimpleNode;
/**
* Pluggable directive that handles the #parse()
* statement in VTL.
*
*
* Notes:
* -----
* 1) The parsed source material can only come from somewhere in
* the TemplateRoot tree for security reasons. There is no way
* around this. If you want to include content from elsewhere on
* your disk, use a link from somwhere under Template Root to that
* content.
*
* 2) There is a limited parse depth. It is set as a property
* "directive.parse.max.depth = 10" by default. This 10 deep
* limit is a safety feature to prevent infinite loops.
*
*
* @author Geir Magnusson Jr.
* @author Jason van Zyl
* @author Christoph Reck
* @version $Id: Parse.java 938699 2010-04-27 22:19:26Z nbubna $
*/
public class Parse extends InputBase
{
private int maxDepth;
/**
* Return name of this directive.
* @return The name of this directive.
*/
public String getName()
{
return "parse";
}
/**
* Return type of this directive.
* @return The type of this directive.
*/
public int getType()
{
return LINE;
}
/**
* Init's the #parse directive.
* @param rs
* @param context
* @param node
* @throws TemplateInitException
*/
public void init(RuntimeServices rs, InternalContextAdapter context, Node node)
throws TemplateInitException
{
super.init(rs, context, node);
this.maxDepth = rsvc.getInt(RuntimeConstants.PARSE_DIRECTIVE_MAXDEPTH, 10);
}
/**
* iterates through the argument list and renders every
* argument that is appropriate. Any non appropriate
* arguments are logged, but render() continues.
* @param context
* @param writer
* @param node
* @return True if the directive rendered successfully.
* @throws IOException
* @throws ResourceNotFoundException
* @throws ParseErrorException
* @throws MethodInvocationException
*/
public boolean render( InternalContextAdapter context,
Writer writer, Node node)
throws IOException, ResourceNotFoundException, ParseErrorException,
MethodInvocationException
{
/*
* if rendering is no longer allowed (after a stop), we can safely
* skip execution of all the parse directives.
*/
if(!context.getAllowRendering())
{
return true;
}
/*
* did we get an argument?
*/
if ( node.jjtGetChild(0) == null)
{
rsvc.getLog().error("#parse() null argument");
return false;
}
/*
* does it have a value? If you have a null reference, then no.
*/
Object value = node.jjtGetChild(0).value( context );
if ( value == null)
{
rsvc.getLog().error("#parse() null argument");
return false;
}
/*
* get the path
*/
String sourcearg = value.toString();
/*
* check to see if the argument will be changed by the event cartridge
*/
String arg = EventHandlerUtil.includeEvent( rsvc, context, sourcearg, context.getCurrentTemplateName(), getName());
/*
* a null return value from the event cartridge indicates we should not
* input a resource.
*/
boolean blockinput = false;
if (arg == null)
blockinput = true;
if (maxDepth > 0)
{
/*
* see if we have exceeded the configured depth.
*/
Object[] templateStack = context.getTemplateNameStack();
if (templateStack.length >= maxDepth)
{
StringBuffer path = new StringBuffer();
for( int i = 0; i < templateStack.length; ++i)
{
path.append( " > " + templateStack[i] );
}
rsvc.getLog().error("Max recursion depth reached (" +
templateStack.length + ')' + " File stack:" +
path);
return false;
}
}
/*
* now use the Runtime resource loader to get the template
*/
Template t = null;
try
{
if (!blockinput)
t = rsvc.getTemplate( arg, getInputEncoding(context) );
}
catch ( ResourceNotFoundException rnfe )
{
/*
* the arg wasn't found. Note it and throw
*/
rsvc.getLog().error("#parse(): cannot find template '" + arg +
"', called at " + Log.formatFileString(this));
throw rnfe;
}
catch ( ParseErrorException pee )
{
/*
* the arg was found, but didn't parse - syntax error
* note it and throw
*/
rsvc.getLog().error("#parse(): syntax error in #parse()-ed template '"
+ arg + "', called at " + Log.formatFileString(this));
throw pee;
}
/**
* pass through application level runtime exceptions
*/
catch( RuntimeException e )
{
rsvc.getLog().error("Exception rendering #parse(" + arg + ") at " +
Log.formatFileString(this));
throw e;
}
catch ( Exception e)
{
String msg = "Exception rendering #parse(" + arg + ") at " +
Log.formatFileString(this);
rsvc.getLog().error(msg, e);
throw new VelocityException(msg, e);
}
if (!blockinput)
{
/**
* Add the template name to the macro libraries list
*/
List macroLibraries = context.getMacroLibraries();
/**
* if macroLibraries are not set create a new one
*/
if (macroLibraries == null)
{
macroLibraries = new ArrayList();
}
context.setMacroLibraries(macroLibraries);
macroLibraries.add(arg);
}
/*
* and render it
*/
try
{
if (!blockinput) {
context.pushCurrentTemplateName(arg);
((SimpleNode) t.getData()).render( context, writer );
}
}
/**
* pass through application level runtime exceptions
*/
catch( RuntimeException e )
{
/**
* Log #parse errors so the user can track which file called which.
*/
rsvc.getLog().error("Exception rendering #parse(" + arg + ") at " +
Log.formatFileString(this));
throw e;
}
catch ( Exception e )
{
String msg = "Exception rendering #parse(" + arg + ") at " +
Log.formatFileString(this);
rsvc.getLog().error(msg, e);
throw new VelocityException(msg, e);
}
finally
{
if (!blockinput)
context.popCurrentTemplateName();
}
/*
* note - a blocked input is still a successful operation as this is
* expected behavior.
*/
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy