private object HandleInvocationException(object o, IInternalContextAdapter context, System.Exception t) { /* * In the event that the invocation of the method * itself throws an exception, we want to catch that * wrap it, and throw. We don't Log here as we want to figure * out which reference threw the exception, so do that * above */ /* * let non-Exception Throwables go... */ if (t is System.Exception) { try { return(EventHandlerUtil.MethodException(rsvc, context, o.GetType(), methodName, (System.Exception)t)); } /** * If the event handler throws an exception, then wrap it * in a MethodInvocationException. Don't pass through RuntimeExceptions like other * similar catchall code blocks. */ catch (System.Exception e) { throw new MethodInvocationException("Invocation of method '" + methodName + "' in " + o.GetType() + " threw exception " + e.ToString(), e, methodName, TemplateName, this.Line, this.Column); } } else { /* * no event cartridge to override. Just throw */ throw new MethodInvocationException("Invocation of method '" + methodName + "' in " + o.GetType() + " threw exception " + t.ToString(), t, methodName, TemplateName, this.Line, this.Column); } }
/// <summary> does the parameters rendering of the included file /// /// </summary> /// <param name="node">AST argument of type StringLiteral or Reference /// </param> /// <param name="context">valid context so we can render References /// </param> /// <param name="writer">output Writer /// </param> /// <returns> boolean success or failure. failures are logged /// </returns> /// <exception cref="IOException"> /// </exception> /// <exception cref="MethodInvocationException"> /// </exception> /// <exception cref="ResourceNotFoundException"> /// </exception> private bool RenderOutput(INode node, IInternalContextAdapter context, System.IO.TextWriter writer) { if (node == null) { rsvc.Log.Error("#include() null argument"); return(false); } /* * does it have a value? If you have a null reference, then no. */ object value = node.Value(context); if (value == null) { rsvc.Log.Error("#include() null argument"); return(false); } /* * Get the path */ string sourcearg = value.ToString(); /* * check to see if the argument will be changed by the event handler */ string arg = EventHandlerUtil.IncludeEvent(rsvc, context, sourcearg, context.CurrentTemplateName, Name); /* * a null return value from the event cartridge indicates we should not * input a resource. */ bool blockinput = false; if (arg == null) { blockinput = true; } Resource resource = null; try { if (!blockinput) { resource = rsvc.GetContent(arg, GetInputEncoding(context)); } } catch (ResourceNotFoundException rnfe) { /* * the arg wasn't found. Note it and throw */ rsvc.Log.Error("#include(): cannot find resource '" + arg + "', called at " + Log.Log.FormatFileString(this)); throw rnfe; } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { rsvc.Log.Error("#include(): arg = '" + arg + "', called at " + Log.Log.FormatFileString(this)); throw e; } catch (System.Exception e) { string msg = "#include(): arg = '" + arg + "', called at " + Log.Log.FormatFileString(this); rsvc.Log.Error(msg, e); throw new VelocityException(msg, e); } /* * note - a blocked input is still a successful operation as this is * expected behavior. */ if (blockinput) { return(true); } else if (resource == null) { return(false); } writer.Write((string)resource.Data); return(true); }
/// <summary> puts the value of the RHS into the context under the key of the LHS</summary> /// <param name="context"> /// </param> /// <param name="writer"> /// </param> /// <returns> True if rendering was sucessful. /// </returns> /// <throws> IOException </throws> /// <throws> MethodInvocationException </throws> public override bool Render(IInternalContextAdapter context, System.IO.TextWriter writer) { /* * Get the RHS node, and its value */ object value = right.Value(context); /* * it's an Error if we don't have a value of some sort AND * it is not allowed by configuration */ if (!allowNull) { if (value == null) { /* * first, are we supposed to say anything anyway? */ if (logOnNull) { bool doit = EventHandlerUtil.ShouldLogOnNullSet(rsvc, context, left.Literal, right.Literal); if (doit && rsvc.Log.DebugEnabled) { rsvc.Log.Debug("RHS of #set statement is null. Context will not be modified. " + Log.FormatFileString(this)); } } string rightReference = null; if (right is ASTExpression) { rightReference = ((ASTExpression)right).LastToken.Image; } EventHandlerUtil.InvalidSetMethod(rsvc, context, leftReference, rightReference, uberInfo); return(false); } } if (value == null && !strictRef) { string rightReference = null; if (right is ASTExpression) { rightReference = ((ASTExpression)right).LastToken.Image; } EventHandlerUtil.InvalidSetMethod(rsvc, context, leftReference, rightReference, uberInfo); /* * if RHS is null, remove simple LHS from context * or call setValue() with a null value for complex LHS */ if (left.GetNumChildren() == 0) { context.Remove(leftReference); } else { left.SetValue(context, (object)null); } return(false); } else { /* * if the LHS is simple, just punch the value into the context * otherwise, use the setValue() method do to it. * Maybe we should always use setValue() */ if (left.GetNumChildren() == 0) { context.Put(leftReference, value); } else { left.SetValue(context, value); } } return(true); }
/// <summary> iterates through the argument list and renders every /// argument that is appropriate. Any non appropriate /// arguments are logged, but render() continues. /// </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) { /* * if rendering is no longer allowed (after a stop), we can safely * skip execution of all the parse directives. */ if (!context.AllowRendering) { return(true); } /* * did we Get an argument? */ if (node.GetChild(0) == null) { rsvc.Log.Error("#parse() null argument"); return(false); } /* * does it have a value? If you have a null reference, then no. */ object value = node.GetChild(0).Value(context); if (value == null) { rsvc.Log.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.CurrentTemplateName, Name); /* * a null return value from the event cartridge indicates we should not * input a resource. */ bool blockinput = false; if (arg == null) { blockinput = true; } if (maxDepth > 0) { /* * see if we have exceeded the configured depth. */ object[] templateStack = context.TemplateNameStack; if (templateStack.Length >= maxDepth) { System.Text.StringBuilder path = new System.Text.StringBuilder(); for (int i = 0; i < templateStack.Length; ++i) { path.Append(" > " + templateStack[i]); } rsvc.Log.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.Log.Error("#parse(): cannot find template '" + arg + "', called at " + Log.Log.FormatFileString(this)); throw rnfe; } catch (ParseErrorException pee) { /* * the arg was found, but didn't parse - syntax Error * note it and throw */ rsvc.Log.Error("#parse(): syntax error in #parse()-ed template '" + arg + "', called at " + Log.Log.FormatFileString(this)); throw pee; } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { rsvc.Log.Error("Exception rendering #parse(" + arg + ") at " + Log.Log.FormatFileString(this)); throw e; } catch (System.Exception e) { string msg = "Exception rendering #parse(" + arg + ") at " + Log.Log.FormatFileString(this); rsvc.Log.Error(msg, e); throw new VelocityException(msg, e); } /** * Add the template name to the macro libraries list */ System.Collections.IList macroLibraries = context.MacroLibraries; /** * if macroLibraries are not set create a new one */ if (macroLibraries == null) { macroLibraries = new System.Collections.ArrayList(); } context.MacroLibraries = macroLibraries; macroLibraries.Add(arg); /* * and render it */ try { if (!blockinput) { context.PushCurrentTemplateName(arg); ((SimpleNode)t.Data).Render(context, writer); } } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { /** * LogMessage #parse errors so the user can track which file called which. */ rsvc.Log.Error("Exception rendering #parse(" + arg + ") at " + Log.Log.FormatFileString(this)); throw e; } catch (System.Exception e) { string msg = "Exception rendering #parse(" + arg + ") at " + Log.Log.FormatFileString(this); rsvc.Log.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); }
/// <summary> gets the value of the reference and outputs it to the /// writer. /// /// </summary> /// <param name="context"> context of data to use in getting value /// </param> /// <param name="writer"> writer to render to /// </param> /// <returns> True if rendering was successful. /// </returns> /// <throws> IOException </throws> /// <throws> MethodInvocationException </throws> public override bool Render(IInternalContextAdapter context, TextWriter writer) { if (referenceType == RUNT) { if (context.AllowRendering) { writer.Write(rootString); } return(true); } object value = Execute((object)null, context); string localNullString = null; /* * 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) { localNullString = GetNullString(context); if (value == null) { if (context.AllowRendering) { writer.Write(escPrefix); writer.Write("\\"); writer.Write(localNullString); } } else { if (context.AllowRendering) { writer.Write(escPrefix); writer.Write(localNullString); } } 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) { if (value is IRenderable && ((IRenderable)value).Render(context, writer)) { return(true); } //UPGRADE_TODO: 在 .NET 中,方法“java.lang.Object.toString”的等效项可能返回不同的值。 "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'" toString = value.ToString(); } if (value == null || toString == null) { /* * write prefix twice, because it's schmoo, so the \ don't escape each other... */ if (context.AllowRendering) { localNullString = GetNullString(context); writer.Write(escPrefix); writer.Write(escPrefix); writer.Write(morePrefix); writer.Write(localNullString); } if (logOnNull && referenceType != QUIET_REFERENCE && log.DebugEnabled) { log.Debug("Null reference [template '" + TemplateName + "', line " + this.Line + ", column " + this.Column + "] : " + this.Literal + " cannot be resolved."); } return(true); } else { /* * non-null processing */ if (context.AllowRendering) { writer.Write(escPrefix); writer.Write(morePrefix); writer.Write(toString); } return(true); } }
/// <summary> gets an Object that 'is' the value of the reference /// /// </summary> /// <param name="o"> unused Object parameter /// </param> /// <param name="context">context used to generate value /// </param> /// <returns> The execution result. /// </returns> /// <throws> MethodInvocationException </throws> public override object Execute(object o, IInternalContextAdapter context) { if (referenceType == RUNT) { return(null); } /* * get the root object from the context */ object result = GetVariableValue(context, rootString); if (result == null && !strictRef) { return(EventHandlerUtil.InvalidGetMethod(rsvc, context, "$" + rootString, (object)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++) { if (strictRef && result == null) { /** * At this point we know that an attempt is about to be made * to call a method or property on a null value. */ string name = GetChild(i).FirstToken.Image; throw new VelocityException("Attempted to access '" + name + "' on a null value at " + Log.FormatFileString(uberInfo.TemplateName, +GetChild(i).Line, GetChild(i).Column)); } previousResult = result; result = GetChild(i).Execute(result, context); if (result == null && !strictRef) // If strict and null then well catch this // next time through the loop { failedChild = i; break; } } if (result == null) { if (failedChild == -1) { result = EventHandlerUtil.InvalidGetMethod(rsvc, context, "$" + rootString, previousResult, null, uberInfo); } else { System.Text.StringBuilder name = new System.Text.StringBuilder("$").Append(rootString); for (int i = 0; i <= failedChild; i++) { INode node = GetChild(i); if (node is ASTMethod) { name.Append(".").Append(((ASTMethod)node).MethodName).Append("()"); } else { name.Append(".").Append(node.FirstToken.Image); } } if (GetChild(failedChild) is ASTMethod) { string methodName = ((ASTMethod)GetChild(failedChild)).MethodName; result = EventHandlerUtil.InvalidMethod(rsvc, context, name.ToString(), previousResult, methodName, uberInfo); } else { string property = GetChild(failedChild).FirstToken.Image; result = EventHandlerUtil.InvalidGetMethod(rsvc, context, name.ToString(), previousResult, property, uberInfo); } } } return(result); } catch (MethodInvocationException mie) { mie.ReferenceName = rootString; throw mie; } }
/// <seealso cref="NVelocity.Runtime.Paser.Node.SimpleNode.Execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter)"> /// </seealso> public override object Execute(object o, IInternalContextAdapter context) { IVelPropertyGet vg = null; try { /* * first, see if we have this information cached. */ IntrospectionCacheData icd = context.ICacheGet(this); /* * if we have the cache data and the class of the object we are * invoked with is the same as that in the cache, then we must * be allright. The last 'variable' is the method name, and * that is fixed in the template :) */ if (icd != null && (o != null) && (icd.ContextData == o.GetType())) { vg = (IVelPropertyGet)icd.Thingy; } else { /* * otherwise, do the introspection, and cache it. Use the * uberspector */ vg = rsvc.Uberspect.GetPropertyGet(o, identifier, uberInfo); if (vg != null && vg.Cacheable && (o != null)) { icd = new IntrospectionCacheData(); icd.ContextData = o.GetType(); icd.Thingy = vg; context.ICachePut(this, icd); } } } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { throw e; } catch (System.Exception e) { string msg = "ASTIdentifier.Execute() : identifier = " + identifier; log.Error(msg, e); throw new VelocityException(msg, e); } /* * we have no getter... punt... */ if (vg == null) { if (strictRef) { throw new MethodInvocationException("Object '" + o.GetType().FullName + "' does not contain property '" + identifier + "'", null, identifier, uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); } else { return(null); } } /* * now try and Execute. If we Get a MIE, throw that * as the app wants to Get these. If not, Log and punt. */ try { return(vg.Invoke(o)); } catch (System.Reflection.TargetInvocationException ite) { /* * if we have an event cartridge, see if it wants to veto * also, let non-Exception Throwables go... */ System.Exception t = ite.GetBaseException(); if (t is System.Exception) { try { return(EventHandlerUtil.MethodException(rsvc, context, o.GetType(), vg.MethodName, (System.Exception)t)); } /** * If the event handler throws an exception, then wrap it * in a MethodInvocationException. Don't pass through RuntimeExceptions like other * similar catchall code blocks. */ catch (System.Exception) { throw new MethodInvocationException("Invocation of method '" + vg.MethodName + "'" + " in " + o.GetType() + " threw exception " + ite.GetBaseException().ToString(), ite.GetBaseException(), vg.MethodName, TemplateName, this.Line, this.Column); } } else { /* * no event cartridge to override. Just throw */ throw new MethodInvocationException("Invocation of method '" + vg.MethodName + "'" + " in " + o.GetType() + " threw exception " + ite.GetBaseException().ToString(), ite.GetBaseException(), vg.MethodName, TemplateName, this.Line, this.Column); } } catch (System.ArgumentException) { return(null); } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { throw e; } catch (System.Exception e) { string msg = "ASTIdentifier() : exception invoking method " + "for identifier '" + identifier + "' in " + o.GetType(); log.Error(msg, e); throw new VelocityException(msg, e); } }