[ https://issues.apache.org/jira/browse/VELOCITY-586?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12628269#action_12628269 ]
Nathan Bubna commented on VELOCITY-586: --------------------------------------- Is this stuff that could be done with an IncludeEventHandler? > Add debugging hooks to #parse > ----------------------------- > > Key: VELOCITY-586 > URL: https://issues.apache.org/jira/browse/VELOCITY-586 > Project: Velocity > Issue Type: Improvement > Components: Engine > Affects Versions: 1.5 > Reporter: Tim White > Priority: Minor > > When you have a page that is made up of a complex web of templates and > #parsed includes, it is critical to be able to quickly see what parts of the > page are really in what file. > To do this, I've hacked #parse to inject debugging information into the > template when a 'debug mode' is engaged. This debug mode is engaged via a > URL parameter. > I also inject this information in the VVS right before the main template is > rendered. In this way, you can create a debug overlay on top of the page in > your browser that shows you where each piece of text is coming from. > I think this probably could better be implemented using hooks, so that a user > could trigger when the debug information was being injected. > I also suggest that the name of the current template, it's resource loader, > etc. be passed into the context, so it can be used to see what template is > where and what loader it came from. > Finally, if there could be a way to conditionally prepend or append a > template to each merged or #parse template, that could also help. > Thanks!!! > 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 javax.servlet.http.HttpSession; > 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.runtime.RuntimeConstants; > import org.apache.velocity.runtime.parser.node.Node; > import org.apache.velocity.runtime.parser.node.SimpleNode; > import com.qwest.velocity.VelocityConstants; > /** > * Pluggable directive that handles the <code>#parse()</code> statement in > VTL. > * > * <pre> > * 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 > * "parse_directive.maxdepth = 10" for example. There is a 20 > iteration > * safety in the event that the parameter isn't set. > * </pre> > * > * @author <a href="mailto:[EMAIL PROTECTED]">Geir Magnusson Jr.</a> > * @author <a href="mailto:[EMAIL PROTECTED]">Jason van Zyl</a> > * @author <a href="mailto:[EMAIL PROTECTED]">Christoph Reck</a> > * @version $Id: Parse.java 463298 2006-10-12 16:10:32Z henning $ > */ > public class Parse extends InputBase { > /** > * 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; > } > /** > * 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("Portal #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("Portal #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; > /* > * see if we have exceeded the configured depth. If it isn't > configured, put a stop at 20 just in case. > */ > Object[] templateStack = context.getTemplateNameStack(); > if (templateStack.length >= > rsvc.getInt(RuntimeConstants.PARSE_DIRECTIVE_MAXDEPTH, 20)) { > StringBuffer path = new StringBuffer(); > for (int i = 0; i < templateStack.length; ++i) { > path.append(" > " + templateStack[i]); > } > rsvc.getLog().error("Portal #parse: 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("Portal #parse(): cannot find > template '" + arg + "', called from template " + > context.getCurrentTemplateName() + " at (" + getLine() + ", " + getColumn() + > ")"); > throw rnfe; > } catch (ParseErrorException pee) { > /* > * the arg was found, but didn't parse - syntax error > note it and throw > */ > rsvc.getLog().error( > "Portal #parse(): syntax error in > #parse()-ed template '" + arg + "', called from template " + > context.getCurrentTemplateName() + " at (" + getLine() + ", " + getColumn() + > ")"); > throw pee; > } > /** > * pass through application level runtime exceptions > */ > catch (RuntimeException e) { > throw e; > } catch (Exception e) { > rsvc.getLog().error("Portal #parse() : arg = " + arg + > '.', e); > return false; > } > /* > * and render it > */ > try { > if (rsvc.getLog().isDebugEnabled()) { > rsvc.getLog().debug("*** Portal #Parse Template > Path: " + t.getName()); > } > > /* Save the name of the main template before resetting > templateName for this include */ > String mainTemplateName = ""; > if (context.get(VelocityConstants.TEMPLATE_NAME_VAR) != > null) { > mainTemplateName = > context.get(VelocityConstants.TEMPLATE_NAME_VAR).toString(); > } > /* Set the name of the current template in the context > for general use */ > context.put(VelocityConstants.TEMPLATE_NAME_VAR, > t.getName()); > /* Check various places to see if debug mode is enabled > */ > boolean debugMode = false; > /* This supports PortalVelocityViewServlet */ > if (context.get(VelocityConstants.DEBUG_ATTRIBUTE) != > null) { > debugMode = true; > } > /* This supports qcms.getMessage() */ > if (context.get("session") != null) { > HttpSession session = (HttpSession) > context.get("session"); > if (session.getAttribute("qCmsDebugger") != > null) { > debugMode = true; > } > } > /* Print Debug start output to browser if debug mode is > on */ > if (debugMode) { > Template startTemplate = > rsvc.getTemplate(VelocityConstants.DEBUG_OUTLINE_START_TEMPLATE, > getInputEncoding(context)); > startTemplate.merge(context, writer); > Template nameTemplate = > rsvc.getTemplate(VelocityConstants.DEBUG_NAME_TEMPLATE, > getInputEncoding(context)); > nameTemplate.merge(context, writer); > } > > if (!blockinput) { > context.pushCurrentTemplateName(arg); > ((SimpleNode) t.getData()).render(context, > writer); > } > > /* Print Debug end output to browser if debug mode is > on */ > if (debugMode) { > Template endTemplate = > rsvc.getTemplate(VelocityConstants.DEBUG_OUTLINE_END_TEMPLATE, > getInputEncoding(context)); > endTemplate.merge(context, writer); > } > /* Restore the templateName variable to match the main > template name */ > context.put(VelocityConstants.TEMPLATE_NAME_VAR, > mainTemplateName); > } > /* > * if it's a MIE, it came from the render.... throw it... > */ > catch (MethodInvocationException e) { > throw e; > } > /** > * pass through application level runtime exceptions > */ > catch (RuntimeException e) { > throw e; > } > catch (Exception e) { > rsvc.getLog().error("Portal #parse: Exception rendering > #parse(" + arg + ')', e); > return false; > } finally { > if (!blockinput) > context.popCurrentTemplateName(); > } > /* > * note - a blocked input is still a successful operation as > this is expected behavior. > */ > return true; > } > } -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online. --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]