/// <summary> /// invokes the method. Returns null if a problem, the /// actual return if the method returns something, or /// an empty string "" if the method returns void /// </summary> public override Object Execute(Object o, IInternalContextAdapter context) { IDuck duck = o as IDuck; object[] parameters = new object[paramCount]; if (duck != null) { EvalParameters(parameters, context); return duck.Invoke(methodName, parameters); } /* * new strategy (strategy!) for introspection. Since we want * to be thread- as well as context-safe, we *must* do it now, * at execution time. There can be no in-node caching, * but if we are careful, we can do it in the context. */ MethodInfo method = null; PropertyInfo property = null; bool preparedAlready = false; object[] methodArguments = new object[paramCount]; try { /* * check the cache */ IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); Type c = o.GetType(); /* * like ASTIdentifier, if we have cache information, and the * Class of Object o is the same as that in the cache, we are * safe. */ EvalParameters(parameters, context); if (introspectionCacheData != null && introspectionCacheData.ContextData == c) { preparedAlready = true; /* * and get the method from the cache */ if (introspectionCacheData.Thingy is MethodInfo) { method = (MethodInfo) introspectionCacheData.Thingy; methodArguments = BuildMethodArgs(method, parameters, paramArrayIndex); } if (introspectionCacheData.Thingy is PropertyInfo) { property = (PropertyInfo) introspectionCacheData.Thingy; } } else { /* * otherwise, do the introspection, and then * cache it */ Object obj = PerformIntrospection(context, c, parameters); if (obj is MethodInfo) { method = (MethodInfo) obj; } if (obj is PropertyInfo) { property = (PropertyInfo) obj; } if (obj != null) { introspectionCacheData = new IntrospectionCacheData(); introspectionCacheData.ContextData = c; introspectionCacheData.Thingy = obj; context.ICachePut(this, introspectionCacheData); } } /* * if we still haven't gotten the method, either we are calling * a method that doesn't exist (which is fine...) or I screwed * it up. */ if (method == null && property == null) { return null; } } catch(Exception ex) { runtimeServices.Error(string.Format("ASTMethod.execute() : exception from introspection : {0}", ex)); throw new RuntimeException( String.Format( "Error during object introspection. Check inner exception for details. Node literal {0} Line {1} Column {2}", base.Literal, Line, Column), ex); } try { /* * get the returned object. It may be null, and that is * valid for something declared with a void return type. * Since the caller is expecting something to be returned, * as long as things are peachy, we can return an empty * String so ASTReference() correctly figures out that * all is well. */ Object obj; if (method == null) { obj = property.GetValue(o, null); } else { if (!preparedAlready) { methodArguments = BuildMethodArgs(method, parameters); } obj = method.Invoke(o, methodArguments); if (obj == null && method.ReturnType == typeof(void)) { obj = String.Empty; } } return obj; } catch(TargetInvocationException targetInvocationException) { /* * 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 */ EventCartridge eventCartridge = context.EventCartridge; /* * if we have an event cartridge, see if it wants to veto * also, let non-Exception Throwables go... */ if (eventCartridge == null) { /* * no event cartridge to override. Just throw */ throw new MethodInvocationException( string.Format("Invocation of method '{0}' in {1} threw exception {2} : {3}", methodName, o.GetType(), targetInvocationException.GetBaseException().GetType(), targetInvocationException.GetBaseException().Message), targetInvocationException.GetBaseException(), methodName); } else { try { return eventCartridge.HandleMethodException(o.GetType(), methodName, targetInvocationException.GetBaseException()); } catch(Exception e) { throw new MethodInvocationException( string.Format("Invocation of method '{0}' in {1} threw exception {2} : {3}", methodName, o.GetType(), e.GetType(), e.Message), e, methodName); } } } catch(Exception e) { runtimeServices.Error( string.Format("ASTMethod.execute() : exception invoking method '{0}' in {1} : {2}", methodName, o.GetType(), e)); throw e; } }
/// <summary> /// invokes the method on the object passed in /// </summary> public override Object Execute(Object o, IInternalContextAdapter context) { bool isString = o.GetType() == typeof(string); bool isDecimal = o.GetType() == typeof(decimal); bool isPrimitive = o.GetType().IsPrimitive; if (identifier == "to_quote" && (isString || isPrimitive || isDecimal)) { return string.Format("\"{0}\"", EscapeDoubleQuote(o.ToString())); } else if (identifier == "to_squote" && (isString || isPrimitive || isDecimal)) { return string.Format("'{0}'", EscapeSingleQuote(o.ToString())); } IDuck duck = o as IDuck; if (duck != null) { return duck.GetInvoke(identifier); } IVelPropertyGet velPropertyGet = null; try { Type c = o.GetType(); // first, see if we have this information cached. IntrospectionCacheData introspectionCacheData = 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 all-right. The last 'variable' is the method name, and // that is fixed in the template :) if (introspectionCacheData != null && introspectionCacheData.ContextData == c) { velPropertyGet = (IVelPropertyGet) introspectionCacheData.Thingy; } else { // otherwise, do the introspection, and cache it velPropertyGet = runtimeServices.Uberspect.GetPropertyGet(o, identifier, uberInfo); if (velPropertyGet != null && velPropertyGet.Cacheable) { introspectionCacheData = new IntrospectionCacheData(c, velPropertyGet); context.ICachePut(this, introspectionCacheData); } } } catch(Exception e) { runtimeServices.Error(string.Format("ASTIdentifier.execute() : identifier = {0} : {1}", identifier, e)); } // we have no executor... punt... if (velPropertyGet == null) return null; // now try and execute. If we get a TargetInvocationException, // throw that as the app wants to get these. If not, log and punt. try { return velPropertyGet.Invoke(o); } catch(TargetInvocationException targetInvocationException) { EventCartridge ec = context.EventCartridge; // if we have an event cartridge, see if it wants to veto // also, let non-Exception Throwables go... if (ec == null) { // no event cartridge to override. Just throw String message = String.Format( "Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", velPropertyGet.MethodName, o != null ? o.GetType().FullName : string.Empty, uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); throw new MethodInvocationException(message, targetInvocationException.InnerException, velPropertyGet.MethodName); } else { try { return ec.HandleMethodException(o.GetType(), velPropertyGet.MethodName, targetInvocationException.InnerException); } catch(Exception) { String message = String.Format( "Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", velPropertyGet.MethodName, o != null ? o.GetType().FullName : string.Empty, uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); throw new MethodInvocationException(message, targetInvocationException.InnerException, velPropertyGet.MethodName); } } } catch(ArgumentException) { return null; } catch(Exception e) { runtimeServices.Error( string.Format("ASTIdentifier() : exception invoking method for identifier '{0}' in {1} : {2}", identifier, o.GetType(), e)); } return null; }
/// <summary> /// invokes the method. Returns null if a problem, the /// actual return if the method returns something, or /// an empty string "" if the method returns void /// </summary> public override Object Execute(Object o, IInternalContextAdapter context) { IDuck duck = o as IDuck; object[] parameters = new object[paramCount]; if (duck != null) { EvalParameters(parameters, context); return(duck.Invoke(methodName, parameters)); } /* * new strategy (strategy!) for introspection. Since we want * to be thread- as well as context-safe, we *must* do it now, * at execution time. There can be no in-node caching, * but if we are careful, we can do it in the context. */ MethodInfo method = null; PropertyInfo property = null; bool preparedAlready = false; object[] methodArguments = new object[paramCount]; try { /* * check the cache */ IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); Type c = o.GetType(); /* * like ASTIdentifier, if we have cache information, and the * Class of Object o is the same as that in the cache, we are * safe. */ EvalParameters(parameters, context); if (introspectionCacheData != null && introspectionCacheData.ContextData == c) { preparedAlready = true; /* * and get the method from the cache */ if (introspectionCacheData.Thingy is MethodInfo) { method = (MethodInfo)introspectionCacheData.Thingy; methodArguments = BuildMethodArgs(method, parameters, paramArrayIndex); } if (introspectionCacheData.Thingy is PropertyInfo) { property = (PropertyInfo)introspectionCacheData.Thingy; } } else { /* * otherwise, do the introspection, and then * cache it */ Object obj = PerformIntrospection(context, c, parameters); if (obj is MethodInfo) { method = (MethodInfo)obj; } if (obj is PropertyInfo) { property = (PropertyInfo)obj; } if (obj != null) { introspectionCacheData = new IntrospectionCacheData(); introspectionCacheData.ContextData = c; introspectionCacheData.Thingy = obj; context.ICachePut(this, introspectionCacheData); } } /* * if we still haven't gotten the method, either we are calling * a method that doesn't exist (which is fine...) or I screwed * it up. */ if (method == null && property == null) { return(null); } } catch (Exception ex) { runtimeServices.Error(string.Format("ASTMethod.execute() : exception from introspection : {0}", ex)); throw new RuntimeException( String.Format( "Error during object introspection. Check inner exception for details. Node literal {0} Line {1} Column {2}", base.Literal, Line, Column), ex); } try { /* * get the returned object. It may be null, and that is * valid for something declared with a void return type. * Since the caller is expecting something to be returned, * as long as things are peachy, we can return an empty * String so ASTReference() correctly figures out that * all is well. */ Object obj; if (method == null) { obj = property.GetValue(o, null); } else { if (!preparedAlready) { methodArguments = BuildMethodArgs(method, parameters); } obj = method.Invoke(o, methodArguments); if (obj == null && method.ReturnType == typeof(void)) { obj = String.Empty; } } return(obj); } catch (TargetInvocationException targetInvocationException) { /* * 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 */ EventCartridge eventCartridge = context.EventCartridge; /* * if we have an event cartridge, see if it wants to veto * also, let non-Exception Throwables go... */ if (eventCartridge == null) { /* * no event cartridge to override. Just throw */ throw new MethodInvocationException( string.Format("Invocation of method '{0}' in {1} threw exception {2} : {3}", methodName, o.GetType(), targetInvocationException.GetBaseException().GetType(), targetInvocationException.GetBaseException().Message), targetInvocationException, methodName); } else { try { return(eventCartridge.HandleMethodException(o.GetType(), methodName, targetInvocationException)); } catch (Exception e) { throw new MethodInvocationException( string.Format("Invocation of method '{0}' in {1} threw exception {2} : {3}", methodName, o.GetType(), e.GetType(), e.Message), e, methodName); } } } catch (Exception e) { runtimeServices.Error( string.Format("ASTMethod.execute() : exception invoking method '{0}' in {1} : {2}", methodName, o.GetType(), e)); throw; } }
/// <summary> /// returns an Iterator to the collection in the #foreach() /// </summary> /// <param name="context"> current context </param> /// <param name="node"> AST node </param> /// <returns>Iterator to do the dataset </returns> private IEnumerator GetIterator(IInternalContextAdapter context, INode node) { // get our list object, and punt if it's null. Object listObject = node.GetChild(2).Value(context); // if we have an event cartridge, get a new value object NVelocity.App.Events.EventCartridge eventCartridge = context.EventCartridge; if (eventCartridge != null) { listObject = eventCartridge.ReferenceInsert(new Stack(), node.GetChild(2).Literal, listObject); } if (listObject == null) { return(null); } // See if we already know what type this is. // Use the introspection cache EnumType type = EnumType.Unknown; IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); Type c = listObject.GetType(); // if we have an entry in the cache, and the Class we have // cached is the same as the Class of the data object // then we are ok if (introspectionCacheData != null && introspectionCacheData.ContextData == c) { // dig the type out of the data object type = ((EnumType)introspectionCacheData.Thingy); } // If we still don't know what this is, // figure out what type of object the list // element is, and get the iterator for it if (type == EnumType.Unknown) { if (listObject.GetType().IsArray) { type = EnumType.Array; } else if (listObject is IDictionary) { type = EnumType.Dictionary; } else if (listObject is ICollection) { type = EnumType.Collection; } else if (listObject is IEnumerable) { type = EnumType.Enumerable; } else if (listObject is IEnumerator) { type = EnumType.Enumeration; } // if we did figure it out, cache it if (type != EnumType.Unknown) { introspectionCacheData = new IntrospectionCacheData(c, type); context.ICachePut(this, introspectionCacheData); } } // now based on the type from either cache or examination... switch (type) { case EnumType.Collection: return(((ICollection)listObject).GetEnumerator()); case EnumType.Enumerable: return(((IEnumerable)listObject).GetEnumerator()); case EnumType.Enumeration: runtimeServices.Warn( string.Format( "Warning! The reference {0} is an Enumeration in the #foreach() loop at [{1},{2}] in template {3}. Because it's not resetable, if used in more than once, this may lead to unexpected results.", node.GetChild(2).FirstToken.Image, Line, Column, context.CurrentTemplateName)); return((IEnumerator)listObject); case EnumType.Array: return(((Array)listObject).GetEnumerator()); case EnumType.Dictionary: return(((IDictionary)listObject).GetEnumerator()); default: /* we have no clue what this is */ runtimeServices.Warn( string.Format( "Could not determine type of enumerator ({0}) in #foreach loop for {1} at [{2},{3}] in template {4}", listObject.GetType().Name, node.GetChild(2).FirstToken.Image, Line, Column, context.CurrentTemplateName)); return(null); } }
/// <summary> /// invokes the method on the object passed in /// </summary> public override Object Execute(Object o, IInternalContextAdapter context) { bool isString = o.GetType() == typeof(string); bool isDecimal = o.GetType() == typeof(decimal); bool isPrimitive = o.GetType().IsPrimitive; if (identifier == "to_quote" && (isString || isPrimitive || isDecimal)) { return(string.Format("\"{0}\"", EscapeDoubleQuote(o.ToString()))); } else if (identifier == "to_squote" && (isString || isPrimitive || isDecimal)) { return(string.Format("'{0}'", EscapeSingleQuote(o.ToString()))); } IDuck duck = o as IDuck; if (duck != null) { return(duck.GetInvoke(identifier)); } IVelPropertyGet velPropertyGet = null; try { Type c = o.GetType(); // first, see if we have this information cached. IntrospectionCacheData introspectionCacheData = 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 all-right. The last 'variable' is the method name, and // that is fixed in the template :) if (introspectionCacheData != null && introspectionCacheData.ContextData == c) { velPropertyGet = (IVelPropertyGet)introspectionCacheData.Thingy; } else { // otherwise, do the introspection, and cache it velPropertyGet = runtimeServices.Uberspect.GetPropertyGet(o, identifier, uberInfo); if (velPropertyGet != null && velPropertyGet.Cacheable) { introspectionCacheData = new IntrospectionCacheData(c, velPropertyGet); context.ICachePut(this, introspectionCacheData); } } } catch (Exception e) { runtimeServices.Error(string.Format("ASTIdentifier.execute() : identifier = {0} : {1}", identifier, e)); } // we have no executor... punt... if (velPropertyGet == null) { return(null); } // now try and execute. If we get a TargetInvocationException, // throw that as the app wants to get these. If not, log and punt. try { return(velPropertyGet.Invoke(o)); } catch (TargetInvocationException targetInvocationException) { EventCartridge ec = context.EventCartridge; // if we have an event cartridge, see if it wants to veto // also, let non-Exception Throwables go... if (ec == null) { // no event cartridge to override. Just throw String message = String.Format( "Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", velPropertyGet.MethodName, o != null ? o.GetType().FullName : string.Empty, uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); throw new MethodInvocationException(message, targetInvocationException.InnerException, velPropertyGet.MethodName); } else { try { return(ec.HandleMethodException(o.GetType(), velPropertyGet.MethodName, targetInvocationException.InnerException)); } catch (Exception) { String message = String.Format( "Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", velPropertyGet.MethodName, o != null ? o.GetType().FullName : string.Empty, uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); throw new MethodInvocationException(message, targetInvocationException.InnerException, velPropertyGet.MethodName); } } } catch (ArgumentException) { return(null); } catch (Exception e) { runtimeServices.Error( string.Format("ASTIdentifier() : exception invoking method for identifier '{0}' in {1} : {2}", identifier, o.GetType(), e)); } return(null); }
/// <summary> /// returns an Iterator to the collection in the #foreach() /// </summary> /// <param name="context"> current context </param> /// <param name="node"> AST node </param> /// <returns>Iterator to do the dataset </returns> private IEnumerator GetIterator(IInternalContextAdapter context, INode node) { // get our list object, and punt if it's null. Object listObject = node.GetChild(2).Value(context); // if we have an event cartridge, get a new value object NVelocity.App.Events.EventCartridge eventCartridge = context.EventCartridge; if (eventCartridge != null) { listObject = eventCartridge.ReferenceInsert(new Stack(), node.GetChild(2).Literal, listObject); } if (listObject == null) { return null; } // See if we already know what type this is. // Use the introspection cache EnumType type = EnumType.Unknown; IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); Type c = listObject.GetType(); // if we have an entry in the cache, and the Class we have // cached is the same as the Class of the data object // then we are ok if (introspectionCacheData != null && introspectionCacheData.ContextData == c) { // dig the type out of the data object type = ((EnumType)introspectionCacheData.Thingy); } // If we still don't know what this is, // figure out what type of object the list // element is, and get the iterator for it if (type == EnumType.Unknown) { if (listObject.GetType().IsArray) { type = EnumType.Array; } else if (listObject is IDictionary) { type = EnumType.Dictionary; } else if (listObject is ICollection) { type = EnumType.Collection; } else if (listObject is IEnumerable) { type = EnumType.Enumerable; } else if (listObject is IEnumerator) { type = EnumType.Enumeration; } // if we did figure it out, cache it if (type != EnumType.Unknown) { introspectionCacheData = new IntrospectionCacheData(c, type); context.ICachePut(this, introspectionCacheData); } } // now based on the type from either cache or examination... switch (type) { case EnumType.Collection: return ((ICollection)listObject).GetEnumerator(); case EnumType.Enumerable: return ((IEnumerable)listObject).GetEnumerator(); case EnumType.Enumeration: runtimeServices.Warn( string.Format( "Warning! The reference {0} is an Enumeration in the #foreach() loop at [{1},{2}] in template {3}. Because it's not resetable, if used in more than once, this may lead to unexpected results.", node.GetChild(2).FirstToken.Image, Line, Column, context.CurrentTemplateName)); return (IEnumerator)listObject; case EnumType.Array: return ((Array)listObject).GetEnumerator(); case EnumType.Dictionary: return ((IDictionary)listObject).GetEnumerator(); default: /* we have no clue what this is */ runtimeServices.Warn( string.Format( "Could not determine type of enumerator ({0}) in #foreach loop for {1} at [{2},{3}] in template {4}", listObject.GetType().Name, node.GetChild(2).FirstToken.Image, Line, Column, context.CurrentTemplateName)); return null; } }
public void ICachePut(Object key, IntrospectionCacheData o) { innerContext.ICachePut(key, o); }
public override object Execute(object o, IInternalContextAdapter context) { MethodInfo methodInfo = null; PropertyInfo propertyInfo = null; bool flag = false; object[] array = this.parameters; object result; try { IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); Type type = o.GetType(); if (introspectionCacheData != null && introspectionCacheData.ContextData == type) { for (int i = 0; i < this.paramCount; i++) { this.parameters[i] = base.GetChild(i + 1).Value(context); } flag = true; if (introspectionCacheData.Thingy is MethodInfo) { methodInfo = (MethodInfo)introspectionCacheData.Thingy; array = this.BuildMethodArgs(methodInfo, this.paramArrayIndex); } if (introspectionCacheData.Thingy is PropertyInfo) { propertyInfo = (PropertyInfo)introspectionCacheData.Thingy; } } else { object obj = this.doIntrospection(context, type); if (obj is MethodInfo) { methodInfo = (MethodInfo)obj; } if (obj is PropertyInfo) { propertyInfo = (PropertyInfo)obj; } if (obj != null) { context.ICachePut(this, new IntrospectionCacheData { ContextData = type, Thingy = obj }); } } if (methodInfo == null && propertyInfo == null) { result = null; return(result); } } catch (System.Exception ex) { this.rsvc.Error("ASTMethod.execute() : exception from introspection : " + ex); throw new RuntimeException(string.Format("Error during object instrospection. Check inner exception for details. Node literal {0} Line {1} Column {2}", base.Literal, base.Line, base.Column), ex); } try { object obj; if (methodInfo != null) { if (!flag) { array = this.BuildMethodArgs(methodInfo); } obj = methodInfo.Invoke(o, array); if (obj == null && methodInfo.ReturnType == typeof(void)) { obj = string.Empty; } } else { obj = propertyInfo.GetValue(o, null); } result = obj; } catch (TargetInvocationException ex2) { EventCartridge eventCartridge = context.EventCartridge; if (eventCartridge != null) { try { result = eventCartridge.HandleMethodException(o.GetType(), this.methodName, ex2.GetBaseException()); return(result); } catch (System.Exception ex3) { throw new MethodInvocationException(string.Concat(new object[] { "Invocation of method '", this.methodName, "' in ", o.GetType(), " threw exception ", ex3.GetType(), " : ", ex3.Message }), ex3, this.methodName); } } throw new MethodInvocationException(string.Concat(new object[] { "Invocation of method '", this.methodName, "' in ", o.GetType(), " threw exception ", ex2.GetBaseException().GetType(), " : ", ex2.GetBaseException().Message }), ex2.GetBaseException(), this.methodName); } catch (System.Exception ex3) { this.rsvc.Error(string.Concat(new object[] { "ASTMethod.execute() : exception invoking method '", this.methodName, "' in ", o.GetType(), " : ", ex3 })); throw ex3; } return(result); }
/// <summary> /// invokes the method on the object passed in /// </summary> public override Object Execute(Object o, IInternalContextAdapter context) { if (identifier == "to_quote" && (o.GetType() == typeof(string) || o.GetType().IsPrimitive || o.GetType() == typeof(decimal))) { return "\"" + EscapeDoubleQuote(o.ToString()) + "\""; } else if (identifier == "to_squote" && (o.GetType() == typeof(string) || o.GetType().IsPrimitive || o.GetType() == typeof(decimal))) { return "'" + EscapeSingleQuote(o.ToString()) + "'"; } IDuck duck = o as IDuck; if (duck != null) { return duck.GetInvoke(identifier); } IVelPropertyGet vg = null; try { Type c = o.GetType(); // 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 && icd.ContextData == c) { vg = (IVelPropertyGet) icd.Thingy; } else { // otherwise, do the introspection, and cache it vg = rsvc.Uberspect.GetPropertyGet(o, identifier, uberInfo); if (vg != null && vg.Cacheable) { icd = new IntrospectionCacheData(c, vg); context.ICachePut(this, icd); } } } catch(Exception e) { rsvc.Error("ASTIdentifier.execute() : identifier = " + identifier + " : " + e); } // we have no executor... punt... if (vg == null) return null; // now try and execute. If we get a TargetInvocationException, // throw that as the app wants to get these. If not, log and punt. try { return vg.Invoke(o); } catch(TargetInvocationException ite) { EventCartridge ec = context.EventCartridge; // if we have an event cartridge, see if it wants to veto // also, let non-Exception Throwables go... if (ec != null) { try { return ec.HandleMethodException(o.GetType(), vg.MethodName, ite.InnerException); } catch(Exception) { String message = String.Format( "Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", vg.MethodName, o != null ? o.GetType().FullName : "", uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); throw new MethodInvocationException(message, ite.InnerException, vg.MethodName); } } else { // no event cartridge to override. Just throw String message = String.Format( "Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", vg.MethodName, o != null ? o.GetType().FullName : "", uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); throw new MethodInvocationException(message, ite.InnerException, vg.MethodName); } } catch(ArgumentException) { return null; } catch(Exception e) { rsvc.Error("ASTIdentifier() : exception invoking method " + "for identifier '" + identifier + "' in " + o.GetType() + " : " + e); } return null; }
/// <summary> invokes the method. Returns null if a problem, the /// parameters return if the method returns something, or /// an empty string "" if the method returns void /// </summary> /// <param name="instance"> /// </param> /// <param name="context"> /// </param> /// <returns> Result or null. /// </returns> /// <throws> MethodInvocationException </throws> public override object Execute(object o, IInternalContextAdapter context) { /* * new strategy (strategery!) for introspection. Since we want * to be thread- as well as context-safe, we *must* do it now, * at execution time. There can be no in-node caching, * but if we are careful, we can do it in the context. */ IVelMethod method = null; object[] params_Renamed = new object[paramCount]; try { /* * sadly, we do need recalc the values of the args, as this can * change from visit to visit */ System.Type[] paramClasses = paramCount > 0 ? new System.Type[paramCount] : new System.Collections.Generic.List <Type>().ToArray(); for (int j = 0; j < paramCount; j++) { params_Renamed[j] = GetChild(j + 1).Value(context); if (params_Renamed[j] != null) { paramClasses[j] = params_Renamed[j].GetType(); } } /* * check the cache */ MethodCacheKey mck = new MethodCacheKey(methodName, paramClasses); IntrospectionCacheData icd = context.ICacheGet(mck); /* * like ASTIdentifier, if we have cache information, and the * Class of Object instance is the same as that in the cache, we are * safe. */ if (icd != null && (o != null && icd.ContextData == o.GetType())) { /* * Get the method from the cache */ method = (IVelMethod)icd.Thingy; } else { /* * otherwise, do the introspection, and then * cache it */ method = rsvc.Uberspect.GetMethod(o, methodName, params_Renamed, new Info(TemplateName, Line, Column)); if ((method != null) && (o != null)) { icd = new IntrospectionCacheData(); icd.ContextData = o.GetType(); icd.Thingy = method; context.ICachePut(mck, icd); } } /* * if we still haven't gotten the method, either we are calling * a method that doesn't exist (which is fine...) or I screwed * it up. */ if (method == null) { if (strictRef) { // Create a parameter list for the exception Error message System.Text.StringBuilder plist = new System.Text.StringBuilder(); for (int i = 0; i < params_Renamed.Length; i++) { System.Type param = paramClasses[i]; plist.Append(param == null ? "null" : param.FullName); if (i < params_Renamed.Length - 1) { plist.Append(", "); } } throw new MethodInvocationException("Object '" + o.GetType().FullName + "' does not contain method " + methodName + "(" + plist + ")", null, methodName, uberInfo.TemplateName, uberInfo.Line, uberInfo.Column); } else { return(null); } } } catch (MethodInvocationException mie) { /* * this can come from the doIntrospection(), as the arg values * are evaluated to find the right method signature. We just * want to propogate it here, not do anything fancy */ throw mie; } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { throw e; } catch (System.Exception e) { /* * can come from the doIntropection() also, from Introspector */ string msg = "ASTMethod.Execute() : exception from introspection"; log.Error(msg, e); throw new VelocityException(msg, e); } try { /* * Get the returned object. It may be null, and that is * valid for something declared with a void return type. * Since the caller is expecting something to be returned, * as long as things are peachy, we can return an empty * String so ASTReference() correctly figures out that * all is well. */ object obj = method.Invoke(o, params_Renamed); if (obj == null) { if (method.ReturnType == System.Type.GetType("System.Void")) { return(""); } } return(obj); } catch (System.Reflection.TargetInvocationException ite) { return(HandleInvocationException(o, context, ite.GetBaseException())); } /** Can also be thrown by method invocation **/ catch (System.ArgumentException t) { return(HandleInvocationException(o, context, t)); } /** * pass through application level runtime exceptions */ catch (System.SystemException e) { throw e; } catch (System.Exception e) { string msg = "ASTMethod.Execute() : exception invoking method '" + methodName + "' in " + o.GetType(); log.Error(msg, e); throw new VelocityException(msg, e); } }
public void ICachePut(object key, IntrospectionCacheData o) { context.ICachePut(key, o); }
public override object Execute(object o, IInternalContextAdapter context) { IVelPropertyGet velPropertyGet = null; try { Type type = o.GetType(); IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); if (introspectionCacheData != null && introspectionCacheData.ContextData == type) { velPropertyGet = (IVelPropertyGet)introspectionCacheData.Thingy; } else { velPropertyGet = this.rsvc.Uberspect.GetPropertyGet(o, this.identifier, this.uberInfo); if (velPropertyGet != null && velPropertyGet.Cacheable) { introspectionCacheData = new IntrospectionCacheData(type, velPropertyGet); context.ICachePut(this, introspectionCacheData); } } } catch (System.Exception ex) { this.rsvc.Error(string.Concat(new object[] { "ASTIdentifier.execute() : identifier = ", this.identifier, " : ", ex })); } object result; if (velPropertyGet == null) { result = null; } else { try { result = velPropertyGet.Invoke(o); return(result); } catch (TargetInvocationException ex2) { EventCartridge eventCartridge = context.EventCartridge; string message; if (eventCartridge != null) { try { result = eventCartridge.HandleMethodException(o.GetType(), velPropertyGet.MethodName, ex2.InnerException); return(result); } catch (System.Exception) { message = string.Format("Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", new object[] { velPropertyGet.MethodName, (o != null) ? o.GetType().FullName : "", this.uberInfo.TemplateName, this.uberInfo.Line, this.uberInfo.Column }); throw new MethodInvocationException(message, ex2.InnerException, velPropertyGet.MethodName); } } message = string.Format("Invocation of method '{0}' in {1}, template {2} Line {3} Column {4} threw an exception", new object[] { velPropertyGet.MethodName, (o != null) ? o.GetType().FullName : "", this.uberInfo.TemplateName, this.uberInfo.Line, this.uberInfo.Column }); throw new MethodInvocationException(message, ex2.InnerException, velPropertyGet.MethodName); } catch (ArgumentException) { result = null; return(result); } catch (System.Exception ex) { this.rsvc.Error(string.Concat(new object[] { "ASTIdentifier() : exception invoking method for identifier '", this.identifier, "' in ", o.GetType(), " : ", ex })); } result = null; } return(result); }
/// <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); } }
private IEnumerator GetIterator(IInternalContextAdapter context, INode node) { object obj = node.GetChild(2).Value(context); IEnumerator result; if (obj == null) { result = null; } else { Foreach.EnumType enumType = Foreach.EnumType.Unknown; IntrospectionCacheData introspectionCacheData = context.ICacheGet(this); Type type = obj.GetType(); if (introspectionCacheData != null && introspectionCacheData.ContextData == type) { enumType = (Foreach.EnumType)introspectionCacheData.Thingy; } if (enumType == Foreach.EnumType.Unknown) { if (obj.GetType().IsArray) { enumType = Foreach.EnumType.Array; } else if (obj is IDictionary) { enumType = Foreach.EnumType.Dictionary; } else if (obj is ICollection) { enumType = Foreach.EnumType.Collection; } else if (obj is IEnumerable) { enumType = Foreach.EnumType.Enumerable; } else if (obj is IEnumerator) { enumType = Foreach.EnumType.Enumeration; } if (enumType != Foreach.EnumType.Unknown) { introspectionCacheData = new IntrospectionCacheData(type, enumType); context.ICachePut(this, introspectionCacheData); } } switch (enumType) { case Foreach.EnumType.Array: result = ((Array)obj).GetEnumerator(); return(result); case Foreach.EnumType.Dictionary: result = ((IDictionary)obj).GetEnumerator(); return(result); case Foreach.EnumType.Collection: result = ((ICollection)obj).GetEnumerator(); return(result); case Foreach.EnumType.Enumeration: this.rsvc.Warn(string.Concat(new object[] { "Warning! The reference ", node.GetChild(2).FirstToken.Image, " is an Enumeration in the #foreach() loop at [", base.Line, ",", base.Column, "] in template ", context.CurrentTemplateName, ". Because it's not resetable, if used in more than once, this may lead to unexpected results." })); result = (IEnumerator)obj; return(result); case Foreach.EnumType.Enumerable: result = ((IEnumerable)obj).GetEnumerator(); return(result); } this.rsvc.Warn(string.Concat(new object[] { "Could not determine type of enumerator (", obj.GetType().Name, ") in #foreach loop for ", node.GetChild(2).FirstToken.Image, " at [", base.Line, ",", base.Column, "] in template ", context.CurrentTemplateName })); result = null; } return(result); }
/// <summary> /// returns an Iterator to the collection in the #foreach() /// </summary> /// <param name="context"> current context </param> /// <param name="node"> AST node </param> /// <returns>Iterator to do the dataset </returns> private IEnumerator GetIterator(IInternalContextAdapter context, INode node) { // get our list object, and punt if it's null. Object listObject = node.GetChild(2).Value(context); if (listObject == null) return null; // See if we already know what type this is. // Use the introspection cache EnumType type = EnumType.Unknown; IntrospectionCacheData icd = context.ICacheGet(this); Type c = listObject.GetType(); // if we have an entry in the cache, and the Class we have // cached is the same as the Class of the data object // then we are ok if (icd != null && icd.ContextData == c) { // dig the type out of the cata object type = ((EnumType) icd.Thingy); } // If we still don't know what this is, // figure out what type of object the list // element is, and get the iterator for it if (type == EnumType.Unknown) { if (listObject.GetType().IsArray) type = EnumType.Array; else if (listObject is IDictionary) type = EnumType.Dictionary; else if (listObject is ICollection) type = EnumType.Collection; else if (listObject is IEnumerable) type = EnumType.Enumerable; else if (listObject is IEnumerator) type = EnumType.Enumeration; // if we did figure it out, cache it if (type != EnumType.Unknown) { icd = new IntrospectionCacheData(c, type); context.ICachePut(this, icd); } } // now based on the type from either cache or examination... switch(type) { case EnumType.Collection: return ((ICollection) listObject).GetEnumerator(); case EnumType.Enumerable: return ((IEnumerable) listObject).GetEnumerator(); case EnumType.Enumeration: rsvc.Warn("Warning! The reference " + node.GetChild(2).FirstToken.Image + " is an Enumeration in the #foreach() loop at [" + Line + "," + Column + "]" + " in template " + context.CurrentTemplateName + ". Because it's not resetable," + " if used in more than once, this may lead to" + " unexpected results."); return (IEnumerator) listObject; case EnumType.Array: return ((Array) listObject).GetEnumerator(); case EnumType.Dictionary: return ((IDictionary) listObject).GetEnumerator(); default: /* we have no clue what this is */ rsvc.Warn("Could not determine type of enumerator (" + listObject.GetType().Name + ") in " + "#foreach loop for " + node.GetChild(2).FirstToken.Image + " at [" + Line + "," + Column + "]" + " in template " + context.CurrentTemplateName); return null; } }