public bool Evaluate(IContext context, TextWriter writer, string logTag, TextReader reader) { SimpleNode simpleNode = null; try { simpleNode = this.ri.Parse(reader, logTag); } catch (ParseException ex) { throw new ParseErrorException(ex.Message, ex); } bool result; if (simpleNode != null) { InternalContextAdapterImpl internalContextAdapterImpl = new InternalContextAdapterImpl(context); internalContextAdapterImpl.PushCurrentTemplateName(logTag); try { try { simpleNode.Init(internalContextAdapterImpl, this.ri); } catch (System.Exception ex2) { this.ri.Error(string.Concat(new object[] { "Velocity.evaluate() : init exception for tag = ", logTag, " : ", ex2 })); } simpleNode.Render(internalContextAdapterImpl, writer); } finally { internalContextAdapterImpl.PopCurrentTemplateName(); } result = true; } else { result = false; } return(result); }
internal void parseTree(IInternalContextAdapter internalContextAdapter) { try { //UPGRADE_ISSUE: The equivalent of constructor 'java.io.BufferedReader.BufferedReader' is incompatible with the expected type in C#. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1109"' TextReader br = new StringReader(macroBody); nodeTree = Enclosing_Instance.runtimeServices.Parse(br, string.Format("VM:{0}", macroName), true); nodeTree.Init(internalContextAdapter, null); } catch (System.Exception e) { Enclosing_Instance.runtimeServices.Error( string.Format("VelocimacroManager.parseTree() : exception {0} : {1}", macroName, e)); } }
/// <summary> /// Renders the macro using the context /// </summary> public override bool Render(IInternalContextAdapter context, TextWriter writer, INode node) { try { // it's possible the tree hasn't been parsed yet, so get // the VMManager to parse and init it if (nodeTree == null) { runtimeServices.Error(string.Format("VM error : {0}. Null AST", macroName)); } else { if (!init) { nodeTree.Init(context, runtimeServices); init = true; } // wrap the current context and add the VMProxyArg objects VMContext vmContext = new VMContext(context, runtimeServices); for (int i = 1; i < argArray.Length; i++) { // we can do this as VMProxyArgs don't change state. They change // the context. VMProxyArg arg = (VMProxyArg)proxyArgHash[argArray[i]]; vmContext.AddVMProxyArg(arg); } // now render the VM nodeTree.Render(vmContext, writer); } } catch (Exception e) { // if it's a MIE, it came from the render.... throw it... if (e is MethodInvocationException) { throw; } runtimeServices.Error(string.Format("VelocimacroProxy.render() : exception VM = #{0}() : {1}", macroName, e)); } return(true); }
/// <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 static bool Evaluate(IContext context, TextWriter writer, String logTag, TextReader reader) { SimpleNode nodeTree = null; try { nodeTree = RuntimeSingleton.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, RuntimeSingleton.RuntimeServices); } catch (Exception exception) { RuntimeSingleton.Error( string.Format("Velocity.evaluate() : init exception for tag = {0} : {1}", logTag, exception)); } // now render, and let any exceptions fly nodeTree.Render(internalContextAdapterImpl, writer); } finally { internalContextAdapterImpl.PopCurrentTemplateName(); } return(true); } return(false); }
/// <summary> does the housekeeping upon creating. If a dynamic type /// it needs to make an AST for further get()/set() operations /// Anything else is constant. /// </summary> private void setup() { switch (type) { case ParserTreeConstants.INTEGER_RANGE: case ParserTreeConstants.REFERENCE: case ParserTreeConstants.OBJECT_ARRAY: case ParserTreeConstants.STRING_LITERAL: case ParserTreeConstants.TEXT: { /* * dynamic types, just render */ constant = false; try { /* * fakie : wrap in directive to get the parser to treat our args as args * it doesn't matter that #include() can't take all these types, because we * just want the parser to consider our arg as a Directive/VM arg rather than * as if inline in schmoo */ String buff = string.Format("#include({0} ) ", callerReference); //ByteArrayInputStream inStream = new ByteArrayInputStream( buff.getBytes() ); //UPGRADE_ISSUE: The equivalent of constructor 'java.io.BufferedReader.BufferedReader' is incompatible with the expected type in C#. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1109"' TextReader br = new StringReader(buff); nodeTree = runtimeServices.Parse(br, string.Format("VMProxyArg:{0}", callerReference), true); /* * now, our tree really is the first DirectiveArg(), and only one */ nodeTree = (SimpleNode)nodeTree.GetChild(0).GetChild(0); /* * sanity check */ if (nodeTree != null && nodeTree.Type != type) { runtimeServices.Error("VMProxyArg.setup() : programmer error : type doesn't match node type."); } /* * init. We can do this as they are only references */ nodeTree.Init(null, runtimeServices); } catch (System.Exception e) { runtimeServices.Error(string.Format("VMProxyArg.setup() : exception {0} : {1}", callerReference, e)); } break; } case ParserTreeConstants.TRUE: { constant = true; staticObject = true; break; } case ParserTreeConstants.FALSE: { constant = true; staticObject = false; break; } case ParserTreeConstants.NUMBER_LITERAL: { constant = true; staticObject = Int32.Parse(callerReference); break; } case ParserTreeConstants.WORD: { /* * this is technically an error... */ runtimeServices.Error( string.Format( "Unsupported arg type : {0} You most likely intended to call a VM with a string literal, so enclose with ' or \" characters. (VMProxyArg.setup())", callerReference)); constant = true; staticObject = new String(callerReference.ToCharArray()); break; } default: { runtimeServices.Error(string.Format(" VMProxyArg.setup() : unsupported type : {0}", callerReference)); } break; } }
/// <summary> Evaluate the argument, convert to a String, and Evaluate again /// (with the same context). /// </summary> /// <param name="context"> /// </param> /// <param name="writer"> /// </param> /// <param name="node"> /// </param> /// <returns> True if the directive rendered successfully. /// </returns> /// <throws> IOException </throws> /// <throws> ResourceNotFoundException </throws> /// <throws> ParseErrorException </throws> /// <throws> MethodInvocationException </throws> public override bool Render(IInternalContextAdapter context, System.IO.TextWriter writer, INode node) { /* * Evaluate the string with the current context. We know there is * exactly one argument and it is a string or reference. */ object value = node.GetChild(0).Value(context); string sourceText; if (value != null) { sourceText = value.ToString(); } else { sourceText = ""; } /* * The new string needs to be parsed since the text has been dynamically generated. */ string templateName = context.CurrentTemplateName; SimpleNode nodeTree = null; try { nodeTree = rsvc.Parse(new StringReader(sourceText), templateName, false); } catch (ParseException pex) { // use the line/column from the template Info info = new Info(templateName, node.Line, node.Column); throw new ParseErrorException(pex.Message, info); } catch (TemplateInitException pex) { Info info = new Info(templateName, node.Line, node.Column); throw new ParseErrorException(pex.Message, info); } /* * now we want to Init and render. Chain the context * to prevent any changes to the current context. */ if (nodeTree != null) { IInternalContextAdapter ica = new EvaluateContext(context, rsvc); ica.PushCurrentTemplateName(templateName); try { try { nodeTree.Init(ica, rsvc); } catch (TemplateInitException pex) { Info info = new Info(templateName, node.Line, node.Column); throw new ParseErrorException(pex.Message, info); } try { /* * now render, and let any exceptions fly */ nodeTree.Render(ica, writer); } catch (ParseErrorException pex) { // convert any parsing errors to the correct line/col Info info = new Info(templateName, node.Line, node.Column); throw new ParseErrorException(pex.Message, info); } } finally { ica.PopCurrentTemplateName(); } return(true); } return(false); }
/// <summary> The major meat of VelocimacroProxy, Init() checks the # of arguments. /// /// </summary> /// <param name="rs"> /// </param> /// <param name="context"> /// </param> /// <param name="node"> /// </param> /// <throws> TemplateInitException </throws> public override void Init(IRuntimeServices rs, IInternalContextAdapter context, INode node) { // there can be multiple threads here so avoid double inits lock (this) { if (!preInit) { base.Init(rs, context, node); // this is a very expensive call (ExtendedProperties is very slow) strictArguments = rs.Configuration.GetBoolean(NVelocity.Runtime.RuntimeConstants.VM_ARGUMENTS_STRICT, false); // support for local context scope feature, where all references are local // we do not have to check this at every invocation of ProxyVMContext localContextScope = rsvc.GetBoolean(NVelocity.Runtime.RuntimeConstants.VM_CONTEXT_LOCALSCOPE, false); // Get the macro call depth limit maxCallDepth = rsvc.GetInt(NVelocity.Runtime.RuntimeConstants.VM_MAX_DEPTH); // Initialize the parsed AST // since this is context independent we need to do this only once so // do it here instead of the render method nodeTree.Init(context, rs); preInit = true; } } // check how many arguments we got int i = node.GetNumChildren(); // Throw exception for invalid number of arguments? if (NumArgs != i) { // If we have a not-yet defined macro, we do Get no arguments because // the syntax tree looks different than with a already defined macro. // But we do know that we must be in a macro definition context somewhere up the // syntax tree. // Check for that, if it is true, suppress the Error message. // Fixes VELOCITY-71. for (INode parent = node.Parent; parent != null;) { if ((parent is ASTDirective) && string.Equals(((ASTDirective)parent).DirectiveName, "macro")) { return; } parent = parent.Parent; } string msg = "VM #" + macroName + ": too " + ((NumArgs > i) ? "few" : "many") + " arguments to macro. Wanted " + NumArgs + " got " + i; if (strictArguments) { /** * indicate col/line assuming it starts at 0 - this will be corrected one call up */ throw new TemplateInitException(msg, context.CurrentTemplateName, 0, 0); } else { rsvc.Log.Debug(msg); return; } } /* now validate that none of the arguments are plain words, (VELOCITY-614) * they should be string literals, references, inline maps, or inline lists */ for (int n = 0; n < i; n++) { INode child = node.GetChild(n); if (child.Type == NVelocity.Runtime.Parser.ParserTreeConstants.JJTWORD) { /* indicate col/line assuming it starts at 0 * this will be corrected one call up */ throw new TemplateInitException("Invalid arg #" + n + " in VM #" + macroName, context.CurrentTemplateName, 0, 0); } } }