public void invokeOnComponent()

in impl/src/main/java/org/apache/myfaces/component/search/SearchExpressionHandlerImpl.java [369:573]


    public void invokeOnComponent(final SearchExpressionContext searchExpressionContext,
            UIComponent previous, String topExpression, final ContextCallback topCallback)
    {
        if (topExpression == null)
        {
            topExpression = "";
        }
        else
        {
            topExpression = topExpression.trim();
        }
        
        // Command pattern to apply the keyword or command to the base and then invoke the callback
        FacesContext facesContext = searchExpressionContext.getFacesContext();

        SearchExpressionHandler handler = facesContext.getApplication().getSearchExpressionHandler();
        
        //Step 1: find base
        //  Case ':' (root)
        char separatorChar = facesContext.getNamingContainerSeparatorChar();
        if (topExpression.charAt(0) == separatorChar)
        {
            UIComponent findBase = ComponentUtils.findRootComponent(previous);
            handler.invokeOnComponent(searchExpressionContext, findBase, topExpression.substring(1), topCallback);
            return;
        }

        //Step 2: Once you have a base where you can start, apply an expression
        if (topExpression.charAt(0) == KEYWORD_PREFIX.charAt(0))
        {
            // A keyword means apply a command over the current source using an expression and the result must be
            // feedback into the algorithm.

            String command = extractKeyword(topExpression, 1, separatorChar);
            final String remaining =
                    command.length()+1 < topExpression.length() ?
                        topExpression.substring(1+command.length()+1) : null;

            // If the keyword is @child, @composite, @form, @namingcontainer, @next, @none, @parent, @previous,
            // @root, @this ,  all commands change the source to be applied the action
            if (remaining != null)
            {
                if (facesContext.getApplication().getSearchKeywordResolver().isLeaf(searchExpressionContext, command))
                {
                    throw new FacesException("Expression cannot have keywords or ids at the right side: "+command);
                }

                this.applyKeyword(searchExpressionContext, previous, command, remaining, new ContextCallback()
                    {
                        @Override
                        public void invokeContextCallback(FacesContext facesContext, UIComponent target)
                        {
                            handler.invokeOnComponent(
                                    searchExpressionContext, target, remaining, topCallback);
                        }
                    });
            }
            else
            {
                // Command completed, apply parent callback
                this.applyKeyword(searchExpressionContext, previous, command, null, topCallback);
            }
            
        }
        else
        {

            //Split expression into tokens and apply loop
            String nextExpression = null;
            String expression;
            if (topExpression.indexOf(":@") > 0)
            {
                int idx = topExpression.indexOf(":@");
                nextExpression = topExpression.substring(idx+1);
                expression = topExpression.substring(0, idx);
            }
            else
            {
                expression = topExpression;
            }

            // Use findComponent(...) passing the expression provided
            UIComponent target = previous.findComponent(expression);
            if (target == null)
            {
                // If no component is found ...
                // First try to find the base component.

                // Extract the base id from the expression string
                int idx = expression.indexOf(separatorChar);
                String base = idx > 0 ? expression.substring(0, idx) : expression;

                // From the context component clientId, check if the base is part of the clientId
                String contextClientId = previous.getClientId(facesContext);
                int startCommon = contextClientId.lastIndexOf(base+facesContext.getNamingContainerSeparatorChar());
                if (startCommon >= 0
                    && (startCommon == 0 || contextClientId.charAt(startCommon-1) == separatorChar )
                    && (startCommon+base.length() <= contextClientId.length()-1 ||
                        contextClientId.charAt(startCommon+base.length()+1) == separatorChar ))
                {
                    // If there is a match, try to find a the first parent component whose id is equals to
                    // the base id
                    UIComponent parent = previous;
                    while (parent != null )
                    {
                        if (base.equals(parent.getId()) && parent instanceof NamingContainer)
                        {
                            break;
                        }
                        else
                        {
                            parent = parent.getParent();
                        }
                    }

                    // if a base component is found ...
                    if (parent != null)
                    {
                        target = parent.findComponent(expression);
                        if (target == null && !searchExpressionContext.getExpressionHints().contains(
                                SearchExpressionHint.SKIP_VIRTUAL_COMPONENTS))
                        {
                            contextClientId = parent.getClientId(facesContext);
                            // If no component is found,
                            String targetClientId = contextClientId.substring(0, startCommon+base.length()) +
                                    expression.substring(base.length());

                            if (nextExpression != null)
                            {
                                final String childExpression = nextExpression;

                                parent.invokeOnComponent(facesContext, targetClientId, new ContextCallback() 
                                {
                                    @Override
                                    public void invokeContextCallback(FacesContext context, UIComponent target)
                                    {
                                        handler.invokeOnComponent(
                                                searchExpressionContext, target, childExpression, topCallback);
                                    }
                                });
                            }
                            else
                            {
                                parent.invokeOnComponent(facesContext, targetClientId, topCallback);
                            }
                            return;
                        }
                    }
                }
            }

            if (target != null)
            {
                if (nextExpression != null)
                {
                    handler.invokeOnComponent(searchExpressionContext, target, nextExpression, topCallback);
                }
                else
                {
                    topCallback.invokeContextCallback(facesContext, target);
                }

                return;
            }

            // At this point if the algorithm hasn't returned and the topExpression does not have any separator char
            // we need to do the search backward using findComponent.
            if (target == null 
                    && searchExpressionContext.getSource() == previous
                    && (topExpression.indexOf(separatorChar + "@") == -1) ) // updated for MYFACES-4695
            {
                UIComponent baseNC = previous.getNamingContainer();
                if (baseNC != null && baseNC.getParent() != null)
                {
                    UIComponent parentNC = getParentNamingContainerUIViewRoot(baseNC.getParent());
                    while (target == null && parentNC != null)
                    {
                        UIComponent parent = parentNC.getParent();
                        target = parentNC.findComponent(expression);
                        if (parent != null)
                        {
                            parentNC = getParentNamingContainerUIViewRoot(parent);
                        }
                        else
                        {
                            parentNC = null;
                        }
                    }
                    if (target != null)
                    {
                        topCallback.invokeContextCallback(facesContext, target);
                        return;
                    }
                }
            }
            
            if (target == null && nextExpression == null)
            {
                return;
            }

            topCallback.invokeContextCallback(facesContext, previous);
        }
        
    }