/**
* Copyright 2013 by dueni.ch
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ch.dueni.faces.view;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
/**
*
* SuppressRebuildViewPhaseListener
can be used on views using
* <f:phaseListener type="com.csg.jsf.view.SuppressRebuildViewPhaseListener" />
* on the page definition to signal to omit the second execution of buildView() in the
* render-response phase. The actual omit of the buildView() call is handled in
* {@link SuppressRebuildViewViewDeclarationLanguageWrapper}.
*
* During JSF post-back requests, buildView() is executed once in the restore-view phase to process * the request parameters (execution phases) and a second time in the render-response phase to make * sure that changed includes or templates are used for the resulting component tree. JSTL tags and * EL expressions like <ui:composition * template="#{condition ? 'include1.xhtml' : 'include2.xhtml'}"> allow to change the used * includes during request processing - that is why the second execution of buildView() in the * render-response phase is necessary. However, if no such dynamic includes are used or the page * author is sure they will not change on the current page, the second execution of buildView() can * be omitted to reduce request processing time. *
** Within restore-view phase after restoring the view, JSF RI put the ViewRoot as a key to * FacesContext attributes map and later uses it to verify that the ViewRoot did not change during * the request. To suppress the second execution of buildView() it is required to know that ViewRoot * did not change after restoring the view. However, to make sure this works with any JSF * implementation we cannot rely on JSF RI specifics. Therefore * {@link SuppressRebuildViewPhaseListener} also adds the restored ViewRoot to FacesContext * attributes map using the key {@link SuppressRebuildViewPhaseListener#RESTORED_VIEWROOT_KEY}. *
* When FacesContext attributes map key * {@link SuppressRebuildViewPhaseListener#RESTORED_VIEWROOT_KEY} contains Boolean.TRUE and the * current ViewRoot to be rendered is the same instance as stored in FacesContext attributes map on * key {@link #RESTORED_VIEWROOT_KEY}, {@link SuppressRebuildViewViewDeclarationLanguageWrapper} * will suppress the second execution of buildView() on that view. *
* * @author hampidu@gmail.com */ public class SuppressRebuildViewPhaseListener implements PhaseListener { /** * The key on FacesContext attributes map to signal omit of second buildView() execution using a * Boolean.TRUE as value - any other value does not suppress buildView() execution. */ public static final String SUPPRESS_REBUILD_VIEW_KEY = "ch.dueni.faces.suppressRebuildView"; /** * The key on FacesContext attributes map to keep the viewRoot as it was built in restore-view * phase to only suppress buildView() execution of viewRoot did not change during the request * processing. */ public static final String RESTORED_VIEWROOT_KEY = "ch.dueni.faces.restoredViewRoot"; private static final long serialVersionUID = 1L; /** * Do nothing during afterPhase processing. */ public void afterPhase(PhaseEvent event) { // do nothing } /** * Add two attributes to FacesContext attributes map to suppress a second execution of buildView() * during render-response phase if the ViewRoot does not change and no includes will change during * the request. The two attributes that are added: *