public Object execute()

in velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java [286:453]


    public Object execute(Object o, InternalContextAdapter context)
        throws MethodInvocationException
    {
        try
        {
            rsvc.getLogContext().pushLogContext(this, uberInfo);

            /*
             *  The only case where 'o' is not null is when this method is called by evaluate().
             *  Its value is not used, but it is a convention meant to allow statements like
             *  #if($invalidReference) *not* to trigger an invalid reference event.
             *  Statements like #if($invalidReference.prop) should *still* trigger an invalid reference event.
             *  Statements like #if($validReference.invalidProp) should not.
             */
            boolean onlyTestingReference = (o != null);

            if (referenceType == RUNT)
                return null;

            /*
             *  get the root object from the context
             */

            Object result = getRootVariableValue(context);

            if (result == null && !strictRef)
            {
                /*
                 * do not trigger an invalid reference if the reference is present, but with a null value
                 * don't either for a quiet reference or inside an #if/#elseif evaluation context
                 */
                if ((referenceType != QUIET_REFERENCE || warnInvalidQuietReferences) &&
                    (numChildren > 0 ||
                        (!context.containsKey(rootString) || warnInvalidNullReferences) &&
                            (!onlyTestingReference || warnInvalidTestedReferences)))
                {
                    result = EventHandlerUtil.invalidGetMethod(rsvc, context,
                            rsvc.getParserConfiguration().getDollarChar() + rootString, null, null, uberInfo);
                }

                if (astAlternateValue != null && (!DuckType.asBoolean(result, true)))
                {
                    result = astAlternateValue.value(context);
                }

                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).getFirstTokenImage();
                        throw new VelocityException("Attempted to access '"
                            + name + "' on a null value at "
                            + StringUtils.formatFileString(uberInfo.getTemplateName(),
                            + jjtGetChild(i).getLine(), jjtGetChild(i).getColumn()),
                            null, rsvc.getLogContext().getStackTrace());
                    }
                    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)
                    {
                        /*
                         * do not trigger an invalid reference if the reference is present, but with a null value
                         * don't either for a quiet reference,
                         * or inside an #if/#elseif evaluation context when there's no child
                         */
                        if ((!context.containsKey(rootString) || warnInvalidNullReferences) &&
                            (referenceType != QUIET_REFERENCE || warnInvalidQuietReferences) &&
                            (!onlyTestingReference || warnInvalidTestedReferences || numChildren > 0))
                        {
                            result = EventHandlerUtil.invalidGetMethod(rsvc, context,
                                    rsvc.getParserConfiguration().getDollarChar() + rootString, previousResult, null, uberInfo);
                        }
                    }
                    else
                    {
                        Node child = jjtGetChild(failedChild);
                        // do not call bad reference handler if the getter is present
                        // (it means the getter has been called and returned null)
                        // do not either for a quiet reference or if the *last* child failed while testing the reference
                        Object getter = context.icacheGet(child);
                        if ((getter == null || warnInvalidNullReferences) &&
                            (referenceType != QUIET_REFERENCE || warnInvalidQuietReferences) &&
                            (!onlyTestingReference || warnInvalidTestedReferences || failedChild < numChildren - 1))
                        {
                            StringBuilder name = new StringBuilder(String.valueOf(rsvc.getParserConfiguration().getDollarChar())).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.getFirstTokenImage());
                                }
                            }

                            if (child instanceof ASTMethod)
                            {
                                String methodName = ((ASTMethod) jjtGetChild(failedChild)).getMethodName();
                                result = EventHandlerUtil.invalidMethod(rsvc, context,
                                    name.toString(), previousResult, methodName, uberInfo);
                            }
                            else
                            {
                                String property = jjtGetChild(failedChild).getFirstTokenImage();
                                result = EventHandlerUtil.invalidGetMethod(rsvc, context,
                                    name.toString(), previousResult, property, uberInfo);
                            }
                        }
                    }
                }

                // Check alternate value at the end of the evaluation
                if (astAlternateValue != null && (!DuckType.asBoolean(result, true)))
                {
                    result = astAlternateValue.value(context);
                }

                return result;
            }
            catch(MethodInvocationException mie)
            {
                mie.setReferenceName(rootString);
                throw mie;
            }
        }
        finally
        {
            rsvc.getLogContext().popLogContext();
        }
    }