public void retargetAttachedObjects()

in impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java [761:914]


    public void retargetAttachedObjects(FacesContext context,
                                        UIComponent topLevelComponent, List<AttachedObjectHandler> handlerList)
    {
        Assert.notNull(context, "context");
        Assert.notNull(topLevelComponent, "topLevelComponent");
        Assert.notNull(handlerList, "handlerList");

        BeanInfo compositeComponentMetadata
                = (BeanInfo) topLevelComponent.getAttributes().get(UIComponent.BEANINFO_KEY);

        if (compositeComponentMetadata == null)
        {
            log.severe("Composite component metadata not found for: " + topLevelComponent.getClientId(context));
            return;
        }

        BeanDescriptor compositeComponentDescriptor = compositeComponentMetadata.getBeanDescriptor();

        List<AttachedObjectTarget> targetList = (List<AttachedObjectTarget>)
                compositeComponentDescriptor.getValue(AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY);

        if (targetList == null || targetList.isEmpty())
        {
            return;
        }

        for (int i = 0, size = handlerList.size(); i < size; i++)
        {
            AttachedObjectHandler currentHandler = handlerList.get(i);
            // In the spec javadoc this variable is referred as forAttributeValue, but
            // note it is also called curTargetName
            String forValue = currentHandler.getFor();
            
            // perf: targetList is always arrayList: see AttachedObjectTargetHandler.apply 
            // and ClientBehaviorHandler.apply 
            for (int k = 0, targetsSize = targetList.size(); k < targetsSize; k++)
            {
                AttachedObjectTarget currentTarget = targetList.get(k);
                FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance();

                if ((forValue != null && forValue.equals(currentTarget.getName())) &&
                        ((currentTarget instanceof ActionSourceAttachedObjectTarget &&
                                currentHandler instanceof ActionSourceAttachedObjectHandler) ||
                                (currentTarget instanceof EditableValueHolderAttachedObjectTarget &&
                                        currentHandler instanceof EditableValueHolderAttachedObjectHandler) ||
                                (currentTarget instanceof ValueHolderAttachedObjectTarget &&
                                        currentHandler instanceof ValueHolderAttachedObjectHandler)))
                {
                    // perf: getTargets return ArrayList - see getTargets implementations
                    List<UIComponent> targets = currentTarget.getTargets(topLevelComponent);
                    for (int l = 0, targetsCount = targets.size(); l < targetsCount; l++)
                    {
                        UIComponent component = targets.get(l);
                        // If we found composite components when traverse the tree
                        // we have to call this one recursively, because each composite component
                        // should have its own AttachedObjectHandler list, filled earlier when
                        // its tag handler is applied.
                        if (UIComponent.isCompositeComponent(component))
                        {
                            // How we obtain the list of AttachedObjectHandler for
                            // the current composite component? It should be a component
                            // attribute or retrieved by a key inside component.getAttributes
                            // map. Since api does not specify any attribute, we suppose
                            // this is an implementation detail and it should be retrieved
                            // from component attribute map.
                            // But this is only the point of the iceberg, because we should
                            // define how we register attached object handlers in this list.
                            // ANS: see CompositeComponentResourceTagHandler.
                            // The current handler should be added to the list, to be chained.
                            // Note that the inner component should have a target with the same name
                            // as "for" attribute
                            mctx.addAttachedObjectHandler(component, currentHandler);

                            List<AttachedObjectHandler> handlers = mctx.getAttachedObjectHandlers(component);

                            retargetAttachedObjects(context, component, handlers);

                            handlers.remove(currentHandler);
                        }
                        else
                        {
                            currentHandler.applyAttachedObject(context, component);
                        }
                        if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
                        {
                            component.markInitialState();
                        }
                    }
                }
                else if ((currentTarget instanceof BehaviorHolderAttachedObjectTarget target &&
                        currentHandler instanceof BehaviorHolderAttachedObjectHandler handler))
                {
                    String eventName = handler.getEventName();
                    boolean isDefaultEvent = target.isDefaultEvent();

                    if ((eventName != null && eventName.equals(currentTarget.getName())) ||
                            (eventName == null && isDefaultEvent))
                    {
                        List<UIComponent> targets = currentTarget.getTargets(topLevelComponent);
                        for (int j = 0, targetssize = targets.size(); j < targetssize; j++)
                        {
                            UIComponent component = targets.get(j);
                            // If we found composite components when traverse the tree
                            // we have to call this one recursively, because each composite component
                            // should have its own AttachedObjectHandler list, filled earlier when
                            // its tag handler is applied.
                            if (UIComponent.isCompositeComponent(component))
                            {
                                if (currentTarget instanceof ClientBehaviorAttachedObjectTarget clientTarget)
                                {
                                    mctx.addAttachedObjectHandler(component,
                                            new ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper(
                                                    (BehaviorHolderAttachedObjectHandler) currentHandler,
                                                    clientTarget.getEvent()));
                                }
                                else
                                {
                                    mctx.addAttachedObjectHandler(component, currentHandler);
                                }

                                List<AttachedObjectHandler> handlers = mctx.getAttachedObjectHandlers(component);

                                retargetAttachedObjects(context, component, handlers);

                                handlers.remove(currentHandler);
                            }
                            else
                            {
                                if (currentHandler instanceof
                                        ClientBehaviorRedirectBehaviorAttachedObjectHandlerWrapper wrapper)
                                {
                                    currentHandler.applyAttachedObject(context,
                                            new ClientBehaviorRedirectEventComponentWrapper(
                                                topLevelComponent,
                                                component,
                                                wrapper.getWrappedEventName(),
                                                eventName,
                                                null));
                                }
                                else
                                {
                                    currentHandler.applyAttachedObject(context, component);
                                }
                            }
                            if (mctx.isUsingPSSOnThisView() && mctx.isMarkInitialState())
                            {
                                component.markInitialState();
                            }
                        }
                    }
                }
            }
        }
    }