diff --git a/faces b/faces index aa60910be6..321e6fae1c 160000 --- a/faces +++ b/faces @@ -1 +1 @@ -Subproject commit aa60910be665e2c29fa11a19280fa165420b77f5 +Subproject commit 321e6fae1c129e3721513b8d61549f81eb4583c1 diff --git a/impl/src/main/java/org/glassfish/mojarra/application/view/FaceletViewHandlingStrategy.java b/impl/src/main/java/org/glassfish/mojarra/application/view/FaceletViewHandlingStrategy.java index c31918fb0a..bb85025ef8 100644 --- a/impl/src/main/java/org/glassfish/mojarra/application/view/FaceletViewHandlingStrategy.java +++ b/impl/src/main/java/org/glassfish/mojarra/application/view/FaceletViewHandlingStrategy.java @@ -248,9 +248,7 @@ public UIViewRoot restoreView(FacesContext context, String viewId) { String clientId = viewRoot.getClientId(context); Object stateObj = state.get(clientId); if (stateObj != null) { - context.getAttributes().put(ViewScopeManager.RESTORE_VIEW_SCOPE_ONLY, true); - viewRoot.restoreState(context, stateObj); - context.getAttributes().remove(ViewScopeManager.RESTORE_VIEW_SCOPE_ONLY); + viewRoot.restoreViewScopeState(context, stateObj); } } } diff --git a/impl/src/main/java/org/glassfish/mojarra/application/view/ViewScopeManager.java b/impl/src/main/java/org/glassfish/mojarra/application/view/ViewScopeManager.java index accd445eba..ac10b5aafe 100644 --- a/impl/src/main/java/org/glassfish/mojarra/application/view/ViewScopeManager.java +++ b/impl/src/main/java/org/glassfish/mojarra/application/view/ViewScopeManager.java @@ -72,10 +72,6 @@ public class ViewScopeManager implements HttpSessionListener, ViewMapListener { * Stores the view map id. */ public static final String VIEW_MAP_ID = "org.glassfish.mojarra.application.view.viewMapId"; - /** - * Stores the constant indicating that only the view scope must be restored. - */ - public static final String RESTORE_VIEW_SCOPE_ONLY = "org.glassfish.mojarra.application.view.restoreViewScopeOnly"; /** * Stores the constant to keep track of the ViewScopeManager. */ diff --git a/impl/src/test/java/org/glassfish/mojarra/component/UIViewRootTest.java b/impl/src/test/java/org/glassfish/mojarra/component/UIViewRootTest.java index b14874ed8d..5da90b5e1a 100644 --- a/impl/src/test/java/org/glassfish/mojarra/component/UIViewRootTest.java +++ b/impl/src/test/java/org/glassfish/mojarra/component/UIViewRootTest.java @@ -18,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.when; import java.lang.reflect.Method; @@ -38,6 +39,9 @@ public class UIViewRootTest { + private static final String SAVED_VIEW_MAP_ID = "savedViewMapId"; + private static final String REPLACEMENT_VIEW_MAP_ID = "replacementViewMapId"; + @Test public void testViewMapPostConstructViewMapEvent() { FacesContext facesContext = Mockito.mock(FacesContext.class); @@ -131,6 +135,89 @@ public void testViewMapSaveAndRestoreState() { setFacesContext(null); } + @Test + public void testViewMapRestoreViewScopeState() { + FacesContext facesContext = Mockito.mock(FacesContext.class); + Application application = Mockito.mock(Application.class); + ExternalContext externalContext = Mockito.mock(ExternalContext.class); + HashMap attributes = new HashMap<>(); + HashMap sessionMap = new HashMap<>(); + + setFacesContext(facesContext); + + when(facesContext.getAttributes()).thenReturn(attributes); + when(facesContext.getApplication()).thenReturn(application); + when(application.getProjectStage()).thenReturn(ProjectStage.UnitTest); + when(facesContext.getExternalContext()).thenReturn(externalContext); + when(externalContext.getApplicationMap()).thenReturn(null); + when(externalContext.getSessionMap()).thenReturn(sessionMap); + + UIViewRoot viewRoot1 = new UIViewRoot(); + viewRoot1.setRenderKitId("HTML_BASIC_TEST"); + viewRoot1.getTransientStateHelper().putTransient(ViewScopeManager.VIEW_MAP_ID, SAVED_VIEW_MAP_ID); + viewRoot1.getViewMap().put("one", "one"); + Object saved = viewRoot1.saveState(facesContext); + + Map viewMaps = new HashMap<>(); + viewMaps.put(SAVED_VIEW_MAP_ID, viewRoot1.getViewMap()); + sessionMap.put(ViewScopeManager.ACTIVE_VIEW_MAPS, viewMaps); + + UIViewRoot viewRoot2 = new UIViewRoot(); + viewRoot2.restoreViewScopeState(facesContext, saved); + + assertEquals("one", viewRoot2.getViewMap().get("one")); + assertNull(viewRoot2.getRenderKitId()); + + setFacesContext(null); + } + + @Test + public void testViewMapRestoreStateAfterRestoreViewScopeState() { + FacesContext facesContext = Mockito.mock(FacesContext.class); + Application application = Mockito.mock(Application.class); + ExternalContext externalContext = Mockito.mock(ExternalContext.class); + HashMap attributes = new HashMap<>(); + HashMap sessionMap = new HashMap<>(); + + setFacesContext(facesContext); + + when(facesContext.getAttributes()).thenReturn(attributes); + when(facesContext.getApplication()).thenReturn(application); + when(application.getProjectStage()).thenReturn(ProjectStage.UnitTest); + when(facesContext.getExternalContext()).thenReturn(externalContext); + when(externalContext.getApplicationMap()).thenReturn(null); + when(externalContext.getSessionMap()).thenReturn(sessionMap); + + UIViewRoot viewRoot1 = new UIViewRoot(); + viewRoot1.getTransientStateHelper().putTransient(ViewScopeManager.VIEW_MAP_ID, SAVED_VIEW_MAP_ID); + viewRoot1.getViewMap().put("one", "one"); + Object saved = viewRoot1.saveState(facesContext); + + /* + * The saved view map is no longer among the active view maps, e.g. LRU-evicted or gone with an expired session. + */ + Map viewMaps = new HashMap<>(); + sessionMap.put(ViewScopeManager.ACTIVE_VIEW_MAPS, viewMaps); + + UIViewRoot viewRoot2 = new UIViewRoot(); + viewRoot2.restoreViewScopeState(facesContext, saved); + + /* + * Simulate our ViewScopeManager minting a replacement view map while the view is being built. + */ + Map replacementViewMap = viewRoot2.getViewMap(); + replacementViewMap.put("two", "two"); + viewMaps.put(REPLACEMENT_VIEW_MAP_ID, replacementViewMap); + viewRoot2.getTransientStateHelper().putTransient(ViewScopeManager.VIEW_MAP_ID, REPLACEMENT_VIEW_MAP_ID); + + viewRoot2.restoreState(facesContext, saved); + + assertEquals(REPLACEMENT_VIEW_MAP_ID, viewRoot2.getTransientStateHelper().getTransient(ViewScopeManager.VIEW_MAP_ID)); + assertEquals("two", viewRoot2.getViewMap().get("two")); + + setFacesContext(null); + } + private void setFacesContext(FacesContext facesContext) { try { Method method = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class);