/** * gets an Object that 'is' the value of the reference * * @param o unused Object parameter * @param context context used to generate value * @return The execution result. * @throws MethodInvocationException */ public Object execute(Object o, InternalContextAdapter context) throws MethodInvocationException { 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, // getDollarBang() + rootString, null, null, uberInfo); return result; } /* * 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 = jjtGetChild(i).getFirstToken().image; throw new VelocityException( "Attempted to access '" + name + "' on a null value at " + Log.formatFileString( uberInfo.getTemplateName(), +jjtGetChild(i).getLine(), jjtGetChild(i).getColumn())); } previousResult = result; result = jjtGetChild(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, // getDollarBang() + rootString, previousResult, null, // uberInfo); } else { StringBuffer name = new StringBuffer(getDollarBang()).append(rootString); for (int i = 0; i <= failedChild; i++) { Node node = jjtGetChild(i); if (node instanceof ASTMethod) { name.append(".").append(((ASTMethod) node).getMethodName()).append("()"); } else { name.append(".").append(node.getFirstToken().image); } } if (jjtGetChild(failedChild) instanceof ASTMethod) { String methodName = ((ASTMethod) jjtGetChild(failedChild)).getMethodName(); // result = EventHandlerUtil.invalidMethod(rsvc, context, // name.toString(), previousResult, methodName, // uberInfo); } else { String property = jjtGetChild(failedChild).getFirstToken().image; // result = EventHandlerUtil.invalidGetMethod(rsvc, context, // name.toString(), previousResult, property, uberInfo); } } } return result; } catch (MethodInvocationException mie) { mie.setReferenceName(rootString); throw mie; } }
/** * @see * org.apache.velocity.runtime.parser.node.SimpleNode#init(org.apache.velocity.context.InternalContextAdapter, * java.lang.Object) */ public Object init(InternalContextAdapter context, Object data) throws TemplateInitException { super.init(context, data); strictEscape = rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE, false); strictRef = rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false); toStringNullCheck = rsvc.getBoolean(RuntimeConstants.DIRECTIVE_IF_TOSTRING_NULLCHECK, true); /* * the only thing we can do in init() is getRoot() * as that is template based, not context based, * so it's thread- and context-safe */ rootString = getRoot().intern(); numChildren = jjtGetNumChildren(); // This is an expensive call, so get it now. literal = literal(); /* * and if appropriate... */ if (numChildren > 0) { Node lastNode = jjtGetChild(numChildren - 1); if (lastNode instanceof ASTIndex) astIndex = (ASTIndex) lastNode; else identifier = lastNode.getFirstToken().image; } /* * make an uberinfo - saves new's later on */ uberInfo = new Info(getTemplateName(), getLine(), getColumn()); /* * track whether we log invalid references */ logOnNull = rsvc.getBoolean(RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, true); /** * In the case we are referencing a variable with #if($foo) or #if( ! $foo) then we allow * variables to be undefined and we set strictRef to false so that if the variable is undefined * an exception is not thrown. */ if (strictRef && numChildren == 0) { logOnNull = false; // Strict mode allows nulls Node node = this.jjtGetParent(); if (node instanceof ASTNotNode // #if( ! $foo) || node instanceof ASTExpression // #if( $foo ) || node instanceof ASTOrNode // #if( $foo || ... || node instanceof ASTAndNode) // #if( $foo && ... { // Now scan up tree to see if we are in an If statement while (node != null) { if (node instanceof ASTIfStatement) { strictRef = false; break; } node = node.jjtGetParent(); } } } return data; }