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;
}