/// <summary> /// initializes the document. init() is not longer /// dependant upon context, but we need to let the /// init() carry the template name down through for VM /// namespace features /// </summary> public void InitDocument() { // send an empty InternalContextAdapter down into the AST to initialize it InternalContextAdapterImpl internalContextAdapterImpl = new InternalContextAdapterImpl(new VelocityContext()); try { // put the current template name on the stack internalContextAdapterImpl.PushCurrentTemplateName(name); // init the AST ((SimpleNode) data).Init(internalContextAdapterImpl, runtimeServices); } finally { // in case something blows up... // pull it off for completeness internalContextAdapterImpl.PopCurrentTemplateName(); } }
/// <summary> /// The AST node structure is merged with the /// context to produce the final output. /// /// Throws IOException if failure is due to a file related /// issue, and Exception otherwise /// </summary> /// <param name="context">Context with data elements accessed by template</param> /// <param name="writer">writer for rendered template</param> /// <exception cref="ResourceNotFoundException"> /// if template not found from any available source. /// </exception> /// <exception cref="ParseErrorException"> /// if template cannot be parsed due to syntax (or other) error. /// </exception> /// <exception cref="System.Exception"> /// anything else. /// </exception> public void Merge(IContext context, TextWriter writer) { // we shouldn't have to do this, as if there is an error condition, // the application code should never get a reference to the // Template if (errorCondition != null) { throw errorCondition; } if (data != null) { // create an InternalContextAdapter to carry the user Context down // into the rendering engine. Set the template name and render() InternalContextAdapterImpl internalContextAdapterImpl = new InternalContextAdapterImpl(context); try { internalContextAdapterImpl.PushCurrentTemplateName(name); internalContextAdapterImpl.CurrentResource = this; ((SimpleNode) data).Render(internalContextAdapterImpl, writer); } finally { // lets make sure that we always clean up the context internalContextAdapterImpl.PopCurrentTemplateName(); internalContextAdapterImpl.CurrentResource = null; } } else { // this shouldn't happen either, but just in case. String msg = "Template.merge() failure. The document is null, most likely due to parsing error."; runtimeServices.Error(msg); throw new System.Exception(msg); } }
/// <summary> /// Renders the input reader using the context into the output writer. /// To be used when a template is dynamically constructed, or want to /// use Velocity as a token replacer. /// </summary> /// <param name="context">context to use in rendering input string</param> /// <param name="writer"> Writer in which to render the output</param> /// <param name="logTag"> string to be used as the template name for log messages in case of error</param> /// <param name="reader">Reader containing the VTL to be rendered</param> /// <returns>true if successful, false otherwise. If false, see Velocity runtime log</returns> public bool Evaluate(IContext context, TextWriter writer, String logTag, TextReader reader) { SimpleNode nodeTree = null; try { nodeTree = runtimeInstance.Parse(reader, logTag); } catch(ParseException parseException) { throw new ParseErrorException(parseException.Message, parseException); } // now we want to init and render if (nodeTree != null) { InternalContextAdapterImpl internalContextAdapterImpl = new InternalContextAdapterImpl(context); internalContextAdapterImpl.PushCurrentTemplateName(logTag); try { try { nodeTree.Init(internalContextAdapterImpl, runtimeInstance); } catch(System.Exception e) { runtimeInstance.Error(string.Format("Velocity.evaluate() : init exception for tag = {0} : {1}", logTag, e)); } // now render, and let any exceptions fly nodeTree.Render(internalContextAdapterImpl, writer); } finally { internalContextAdapterImpl.PopCurrentTemplateName(); } return true; } return false; }