public UIViewRoot restoreView()

in impl/src/main/java/org/apache/myfaces/view/facelets/PartialStateManagementStrategy.java [157:424]


    public UIViewRoot restoreView (FacesContext context, String viewId, String renderKitId)
    {
        Map<String, Object> states;
        UIViewRoot view = null;
        
        ResponseStateManager manager =
                getRenderKitFactory().getRenderKit(context, renderKitId).getResponseStateManager();

        // The value returned here is expected to be false (set by RestoreViewExecutor), but
        //we don't know if some ViewHandler wrapper could change it, so it is better to save the value.
        final boolean oldContextEventState = context.isProcessingEvents();
        
        // Get previous state from ResponseStateManager.
        Object[] state = (Object[]) manager.getState(context, viewId);
        if (state == null)
        {
            //No state could be restored, return null causing ViewExpiredException
            return null;
        }
        
        if (state[1] instanceof Object[] fullState)
        { 
            view = (UIViewRoot) internalRestoreTreeStructure((TreeStructComponent)fullState[0]);

            if (view != null)
            {
                context.setViewRoot (view);
                view.processRestoreState(context, fullState[1]);
                
                // If the view is restored fully, it is necessary to refresh RequestViewContext, otherwise at
                // each ajax request new components associated with @ResourceDependency annotation will be added
                // to the tree, making the state bigger without real need.
                RequestViewContext.getCurrentInstance(context).
                        refreshRequestViewContext(context, view);
                
                if (fullState.length == 3 && fullState[2] != null)
                {
                    context.setResourceLibraryContracts((List) UIComponentBase.
                        restoreAttachedState(context, fullState[2]));
                }
            }
        }
        else
        {
            // Per the spec: build the view.
            ViewDeclarationLanguage vdl = _vdlFactory.getViewDeclarationLanguage(viewId);
            Object faceletViewState = null;
            try
            {
                ViewMetadata metadata = vdl.getViewMetadata (context, viewId);
                
                if (metadata != null)
                {
                    view = metadata.createMetadataView(context);
                    
                    // If no view and response complete there is no need to continue
                    if (view == null && context.getResponseComplete())
                    {
                        return null;
                    }
                }
                if (view == null)
                {
                    view = context.getApplication().getViewHandler().createView(context, viewId);
                }
                
                context.setViewRoot(view); 
                boolean skipBuildView = false;
                if (state[1] != null)
                {
                    // Since Faces 2.2, UIViewRoot.restoreViewScopeState() must be called, but
                    // to get the state of the root, it is necessary to force calculate the
                    // id from this location. Remember in this point, PSS is enabled, so the
                    // code match with the assigment done in 
                    // FaceletViewDeclarationLanguage.buildView()
                    states = (Map<String, Object>) state[1];
                    faceletViewState = UIComponentBase.restoreAttachedState(
                            context,states.get(ComponentSupport.FACELET_STATE_INSTANCE));
                    if (faceletViewState != null && _viewPoolProcessor != null)
                    {
                        ViewPool viewPool = _viewPoolProcessor.getViewPool(context, view);
                        if (viewPool != null)
                        {
                            ViewStructureMetadata viewMetadata = viewPool.retrieveDynamicViewStructureMetadata(
                                context, view, (FaceletState) faceletViewState);
                            if (viewMetadata != null)
                            {
                                ViewEntry entry = viewPool.popDynamicStructureView(context, view,
                                        (FaceletState) faceletViewState);
                                if (entry != null)
                                {
                                    skipBuildView = true;
                                    _viewPoolProcessor.cloneAndRestoreView(context, view, entry, viewMetadata);
                                }
                            }
                        }
                    }
                    if (view.getId() == null)
                    {
                        view.setId(view.createUniqueId(context, null));
                    }
                    if (faceletViewState != null)
                    {
                        FaceletState newFaceletState = (FaceletState) view.getAttributes().get(
                                ComponentSupport.FACELET_STATE_INSTANCE);
                        if (newFaceletState != null)
                        {
                            newFaceletState.restoreState(context, 
                                    ((FaceletState)faceletViewState).saveState(context));
                            faceletViewState = newFaceletState;
                        }
                        else
                        {
                            view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE,  faceletViewState);
                        }
                    }
                    if (state.length == 3)
                    {
                        //Jump to where the count is
                        view.getAttributes().put(UNIQUE_ID_COUNTER_KEY, state[2]);
                    }
                    Object viewRootState = states.get(view.getClientId(context));
                    if (viewRootState != null)
                    {
                        try
                        {
                            view.pushComponentToEL(context, view);
                            view.restoreViewScopeState(context, viewRootState);
                        }
                        finally
                        {
                            view.popComponentFromEL(context);
                        }
                    }
                }
                // On RestoreViewExecutor, setProcessingEvents is called first to false
                // and then to true when postback. Since we need listeners registered to PostAddToViewEvent
                // event to be handled, we should enable it again. For partial state saving we need this listeners
                // be called from here and relocate components properly.
                if (!skipBuildView)
                {
                    try 
                    {
                        context.setProcessingEvents (true);
                        vdl.buildView(context, view);
                        // In the latest code related to PostAddToView, it is
                        // triggered no matter if it is applied on postback. It seems that MYFACES-2389, 
                        // TRINIDAD-1670 and TRINIDAD-1671 are related.
                        subscribeListeners(view);
                    }
                    finally
                    {
                        context.setProcessingEvents (oldContextEventState);
                    }
                }
            }
            catch (Throwable e)
            {
                throw new FacesException ("unable to create view \"" + viewId + '"', e);
            }

            // Stateless mode only for transient views and non stateless mode for
            // stateful views. This check avoid apply state over a stateless view.
            boolean statelessMode = manager.isStateless(context, viewId);
            if (statelessMode && !view.isTransient())
            {
                throw new IllegalStateException("View is not transient");
            }
            if (!statelessMode && view.isTransient())
            {
                throw new IllegalStateException("Cannot apply state over stateless view");
            }
            
            if (state[1] != null)
            {
                states = (Map<String, Object>) state[1];
                //Save the last unique id counter key in UIViewRoot
                Integer lastUniqueIdCounter = (Integer) view.getAttributes().get(UNIQUE_ID_COUNTER_KEY);
                // Retrieve the facelet state before restore anything. The reason is
                // it could be necessary to restore the bindings map from here.
                FaceletState oldFaceletState = (FaceletState) view.getAttributes().get(
                        ComponentSupport.FACELET_STATE_INSTANCE);
                
                // Visit the children and restore their state.
                boolean emptyState = false;
                boolean containsFaceletState = states.containsKey(ComponentSupport.FACELET_STATE_INSTANCE);
                if (states.isEmpty())
                {
                    emptyState = true; 
                }
                else if (states.size() == 1 && containsFaceletState)
                {
                    emptyState = true; 
                }

                //Restore state of current components
                if (!emptyState)
                {
                    // Check if there is only one component state
                    // and that state is UIViewRoot instance (for example when using ViewScope)
                    if ((states.size() == 1 && !containsFaceletState)
                            || (states.size() == 2 && containsFaceletState))
                    {
                        Object viewState = states.get(view.getClientId(context));
                        if (viewState != null)
                        {
                            restoreViewRootOnlyFromMap(context,viewState, view);
                        }
                        else
                        {
                            //The component is not viewRoot, restore as usual.
                            restoreStateFromMap(context, states, view);
                        }
                    }
                    else
                    {
                        restoreStateFromMap(context, states, view);
                    }
                }
                if (faceletViewState != null)
                {
                    // Make sure binding map
                    if (oldFaceletState != null && oldFaceletState.getBindings() != null
                            && !oldFaceletState.getBindings().isEmpty())
                    {
                        // Be sure the new facelet state has the binding map filled from the old one.
                        // When vdl.buildView() is called by restoreView, FaceletState.bindings map is filled, but
                        // when view pool is enabled, vdl.buildView() could restore the view, but create an alternate
                        // FaceletState instance, different from the one restored. In this case, the restored instance
                        // has precedence, but we need to fill bindings map using the entries from the instance that
                        // comes from the view pool.
                        FaceletState newFaceletState = (FaceletState) faceletViewState;
                        for (Map.Entry<String, Map<String, ValueExpression>> entry : 
                                oldFaceletState.getBindings().entrySet())
                        {
                            for (Map.Entry<String, ValueExpression> entry2 : entry.getValue().entrySet())
                            {
                                ValueExpression expr = newFaceletState.getBinding(entry.getKey(), entry2.getKey());
                                if (expr == null)
                                {
                                    newFaceletState.putBinding(entry.getKey(), entry2.getKey(), entry2.getValue());
                                }
                            }
                        }
                        view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE,  newFaceletState);
                    }
                    else
                    {
                        //restore bindings
                        view.getAttributes().put(ComponentSupport.FACELET_STATE_INSTANCE,  faceletViewState);
                    }
                }
                if (lastUniqueIdCounter != null)
                {
                    Integer newUniqueIdCounter = (Integer) view.getAttributes().get(UNIQUE_ID_COUNTER_KEY);
                    if (newUniqueIdCounter != null && lastUniqueIdCounter > newUniqueIdCounter)
                    {
                        // The unique counter was restored by a side effect of 
                        // restoreState() over UIViewRoot with a lower count,
                        // to avoid a component duplicate id exception we need to fix the count.
                        view.getAttributes().put(UNIQUE_ID_COUNTER_KEY, lastUniqueIdCounter);
                    }
                }
                handleDynamicAddedRemovedComponents(context, view, states);
            }
        }
        return view;
    }