public void addComponentResource()

in api/src/main/java/jakarta/faces/component/UIViewRoot.java [199:373]


    public void addComponentResource(FacesContext context, UIComponent componentResource, String target)
    {
        // If the target argument is null
        if (target == null)
        {
            // Look for a target attribute on the component
            target = (String)componentResource.getAttributes().get("target");

            // If there is no target attribute, set target to be the default value head
            if (target == null)
            {
                target = "head";
            }
        }

        // Call getComponentResources to obtain the child list for the given target
        List<UIComponent> componentResources = _getComponentResources(context, target);

        // If the component ID of componentResource matches the ID of a resource
        // that has already been added, remove the old resource.
        String componentId = componentResource.getId();

        if (componentId == null)
        {
            // componentResource can have no id - calling createUniqueId makes us sure that component will have one
            // https://issues.apache.org/jira/browse/MYFACES-2775
            componentId = createUniqueId(context, null);
            componentResource.setId(componentId);
            List<UIComponent> children = componentResource.getChildren();

            /*
             * MYFACES-4631
             * Duplicate ID Exception can occur if children also aren't assigned unique IDs
             * See https://github.com/primefaces-extensions/primefaces-extensions/issues/517
             */
            for(UIComponent child : children) {
                String childId =  createUniqueId(context, null);
                child.setId(childId);
                // TODO - Should we nest down further? 
            }
        }

        // This var helps to handle the case when we try to add a component that already is
        // on the resource list, because PostAddToViewEvent also is sent to components 
        // backing resources. The problem start when a component is already inside
        // componentResources list and we try to relocate it again. This leads to a StackOverflowException
        // so we need to check if a component is and prevent remove and add it again. Note
        // that remove and then add a component trigger another PostAddToViewEvent. The right
        // point to prevent this StackOverflowException is here, because this method is 
        // responsible to traverse the componentResources list and add when necessary.
        boolean alreadyAdded = false;

        //The check is only necessary if the component resource is part of the tree.
        if (componentResource.isInView())
        {
            if (componentResource.getParent() != null &&
                    componentResource.getParent().getId() != null &&
                    componentResource.getParent().getId().equals(JAKARTA_FACES_LOCATION_PREFIX + target))
            {
                // We can assume safely that the component is in place, because there is no way to 
                // put a component resource on a component resource container without call addComponentResource
                // so relocation here will not happen.
                alreadyAdded = true;
            }
            else if (componentId != null)
            {
                for(Iterator<UIComponent> it = componentResources.iterator(); it.hasNext();)
                {
                    UIComponent component = it.next();
                    if(componentId.equals(component.getId()) && componentResource != component)
                    {
                        if (!component.isCachedFacesContext())
                        {
                            try
                            {
                                component.setCachedFacesContext(context);
                                it.remove();
                            }
                            finally
                            {
                                component.setCachedFacesContext(null);
                            }
                        }
                        else
                        {
                            it.remove();
                        }
                    }
                    else if (componentResource == component)
                    {
                        alreadyAdded = true;
                    }
                }
            }
        }
        else if (componentId != null)
        {
            for(Iterator<UIComponent> it = componentResources.iterator(); it.hasNext();)
            {
                UIComponent component = it.next();
                if(componentId.equals(component.getId()) && componentResource != component)
                {
                    if (!component.isCachedFacesContext())
                    {
                        try
                        {
                            component.setCachedFacesContext(context);
                            it.remove();
                        }
                        finally
                        {
                            component.setCachedFacesContext(null);
                        }
                    }
                    else
                    {
                        it.remove();
                    }
                }
                else if (componentResource == component)
                {
                    alreadyAdded = true;
                }
            }
        }

        // Add the component resource to the list
        if (!alreadyAdded)
        {
            if (!componentResource.isCachedFacesContext())
            {
                try
                {
                    componentResource.setCachedFacesContext(context);
                    componentResources.add(componentResource);
                }
                finally
                {
                    componentResource.setCachedFacesContext(context);
                }
            }
            else
            {
                componentResources.add(componentResource);
            }

            // this is required to make dynamic resource loading possible since Faces 2.3
            if (context.getPartialViewContext().isAjaxRequest())
            {
                boolean isBuildingInitialState
                        = context.getAttributes().containsKey(StateManager.IS_BUILDING_INITIAL_STATE);

                // FaceletViewDeclarationLanguage.isRefreshingTransientBuild(context)
                boolean isRefreshTransientBuild
                        = context.getAttributes().containsKey("org.apache.myfaces.REFRESHING_TRANSIENT_BUILD");

                boolean isPostAddToViewEventAfterBuildInitialState =
                        !isBuildingInitialState || (isBuildingInitialState && isRefreshTransientBuild);
                if (isPostAddToViewEventAfterBuildInitialState)
                {
                    try
                    {
                        // RequestViewContext requestViewContext = RequestViewContext.getInstance(context);
                        // requestViewContext.setRenderTarget("head", true, componentResource);
                        Object requestViewContext = REQUEST_VIEW_CONTEXT_GET_INSTANCE.invoke(null, context);
                        REQUEST_VIEW_CONTEXT_SET_RENDER_TARGET.invoke(requestViewContext, "head", true, componentResource);
                    }
                    catch (Exception e)
                    {
                        _getLogger().log(Level.SEVERE, "Could not access RequestViewContext", e);
                    }
                }
            }
        }
    }