@SuppressWarnings("unchecked")
@Override
public UIViewRoot restoreView (FacesContext context, String viewId, String renderKitId)
{
ResponseStateManager manager;
Object state[];
Map<String, Object> states;
UIViewRoot view = null;
// 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.
manager = getRenderKitFactory().getRenderKit(context, renderKitId).getResponseStateManager();
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[])
{
Object[] fullState = (Object[]) state[1];
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 != null && state[1] != null)
{
// Since JSF 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)
{
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.
suscribeListeners(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())