Skipping JSF validation phase to allow model update / invoke application phase
jmsjr Oct 26, 2012 4:37 AMJBoss7.1.1 (Brontes)
Windows7 64-bit
JDK 1.7.0_06 x86 32-bit
I have a need to skip the PROCESS_VALIDATIONS lifecycle phase, but still proceed to the UPDATE_MODEL_VALUES and INVOKE_APPLICATION phases.
Now before someone says to use immediate="true", that will not work for the requirement that I have as that will go straight to the RENDER_RESPONSE phase.
It is basically a Cancel button, but the cancel button itself needs to invoke a method in the backing bean ( e.g. unlock an external resource ), and then close the window. The external resource to unlock is specified as HTML input hidden parameters. Thus, the need to have the UPDATE_MODEL_VALUES, as I need to know the parameters to the external resource to unlock, and the need to have the INVOKE_APPLICATION phase, as I need to invoke a method on the bean to actually unlock the external resource.
Now I am using the example provided here:
http://javalabor.blogspot.com.au/2012/02/jsf-2-conditional-validation.html
So along the same lines, I have:
1) The following in my faces-config.xml file:
{code}
<validator>
<validator-id>javax.faces.Required</validator-id>
<validator-class>xx.yy.zz.SkipRequiredValidator</validator-class>
</validator>
<validator>
<validator-id>javax.faces.Bean</validator-id>
<validator-class>xx.yy.zz.SkipBeanValidator</validator-class>
</validator>
{code}
2) The following class as the SkipRequiredValidator
{code}
package xx.yy.zz;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.RequiredValidator;
/**
* This validator will skip the JSF validation phase if the Submit action
* has the parameter cancel with a value of "Cancel".
*
* This is required as we still want to have the Invoke Application JSF lifecycle
* executed in order to have the workItem unlocked.
*
* @author salvojo
*/
public class SkipRequiredValidator extends RequiredValidator {
private static Logger logger = Logger.getLogger(SkipRequiredValidator.class.getName());
@Override
public void validate(final FacesContext facesContext, final UIComponent component, final Object value) {
if( SkipValidatorUtil.continueValidation(facesContext)) {
logger.log( Level.FINER, "Calling standard validation" );
super.validate(facesContext, component, value);
} else {
logger.log( Level.FINER, "Skipping standard validation" );
}
}
}
{code}
3) The following class as the SkipBeanValidator:
{code}
package xx.yy.zz
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.BeanValidator;
/**
* This validator will skip the JSF validation phase if the Submit action
* has the parameter cancel with a value of "Cancel".
*
* This is required as we still want to have the Invoke Application JSF lifecycle
* executed in order to have the workItem unlocked.
*
* @author salvojo
*/
public class SkipBeanValidator extends BeanValidator {
private static Logger logger = Logger.getLogger(SkipBeanValidator.class.getName());
@Override
public void validate(final FacesContext facesContext, final UIComponent component, final Object value) {
if( SkipValidatorUtil.continueValidation(facesContext)) {
logger.log( Level.FINER, "Calling standard validation" );
super.validate(facesContext, component, value);
} else {
logger.log( Level.FINER, "Skipping standard validation" );
}
}
}
{code}
4) And the utility class
{code}
package xx.yy.zz;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
/**
* Utility method that will:
*
* 1) Check for a request parameter of attribute {@link SkipValidatorUtil#VALIDATE}
*
* 2) If found, return the value of that attribute. It is assumed to be a Boolean.
*
* 3) If not found, checks for a parameter with name that ends in ":cancel" ( the
* text before the colon is the id of the form, which could change ). If found,
* checks that the value of this parameter is "Cancel". If so, sets the
* request parameter of attribute {@link SkipValidatorUtil#VALIDATE} to false.
* If not found, or found but the value of the parameter is not "Cancel",
* then sets the request parameter of attribute {@link SkipValidatorUtil#VALIDATE} to true.
*
* @author salvojo
*/
public final class SkipValidatorUtil {
private static final String VALIDATE = "xx.yy.zz.VALIDATE";
private static Logger logger = Logger.getLogger(SkipValidatorUtil.class.getName());
public static boolean continueValidation(final FacesContext facesContext) {
Boolean continueValidation = (Boolean) facesContext
.getExternalContext()
.getRequestMap()
.get(SkipValidatorUtil.VALIDATE);
if( continueValidation == null ) {
continueValidation = true;
for( Entry<String,String> requestParameter : facesContext
.getExternalContext()
.getRequestParameterMap().entrySet()) {
if( requestParameter.getKey().contains(":cancel") &&
"Cancel".equals(requestParameter.getValue()) ) {
continueValidation = false;
break;
}
}
facesContext
.getExternalContext()
.getRequestMap()
.put(SkipValidatorUtil.VALIDATE, continueValidation);
}
logger.log( Level.FINER, "Validation will be continued? " + continueValidation );
return continueValidation;
}
}
{code}
5) And in my XHTML page, the following snippet:
{code}
<h:inputText id="f_mbrId" value="#{insuranceCase.planMemberId}" required="true">
<h:inputHidden id="workItemTag" value="#{insuranceCase.workItemTag}"/>
<rich:messages/>
<h:commandButton id="cancel" value="Cancel" action="#{insuranceCase.unlock}"></h:commandButton>
{code}
6) After deploying, when I click on the Cancel button, I am STILL getting a validation messages rendered when I leave the f_mbrId HTML input field blank, and the action on the backing bean is never invoked. The following output on the log file shows what happens:
{noformat}
18:41:46,155 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Before Phase: RESTORE_VIEW 1 Session exist: true
18:41:46,156 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap => {2765221448941953821={-5650150279934172176=[Ljava.lang.Object;@37a9aa}, 4523587801893665884={-84153624240172225=[Ljava.lang.Object;@1a46cd2}}
18:41:46,159 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: javax.faces.request.charset => UTF-8
18:41:46,167 FINER [xx.yy.zz.ActionProcessorListener] (http--0.0.0.0-8081-2) Request: j_idt4:f_mbrId =>
18:41:46,184 FINER [xx.yy.zz.ActionProcessorListener] (http--0.0.0.0-8081-2) Request: j_idt4:workItemTag => aasdev1|JSFTESTP|salvojo|R|29628|8603194|aasdev1|STRTCASE|0|9
18:41:46,189 FINER [xx.yy.zz.ActionProcessorListener] (http--0.0.0.0-8081-2) Request: j_idt4:cancel => Cancel
18:41:46,191 FINER [xx.yy.zz.ActionProcessorListener] (http--0.0.0.0-8081-2) Request: javax.faces.ViewState => 4523587801893665884:-84153624240172225
18:41:46,192 FINER [xx.yy.zz.ActionProcessorListener] (http--0.0.0.0-8081-2) Not an initial request to start or open an existing workitem
18:41:46,195 FINER [xx.yy.zz.ActionProcessorListener] (http--0.0.0.0-8081-2) After Phase: RESTORE_VIEW 1 Session exist: true Request Path: null
18:41:46,196 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) After Phase: RESTORE_VIEW 1 Session exist: true Request Path: null
18:41:46,197 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Before Phase: APPLY_REQUEST_VALUES 2 Session exist: true
18:41:46,197 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap => {2765221448941953821={-5650150279934172176=[Ljava.lang.Object;@37a9aa}, 4523587801893665884={-84153624240172225=[Ljava.lang.Object;@1a46cd2}}
18:41:46,199 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: javax.faces.request.charset => UTF-8
18:41:46,200 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) After Phase: APPLY_REQUEST_VALUES 2 Session exist: true Request Path: null
18:41:46,201 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Before Phase: PROCESS_VALIDATIONS 3 Session exist: true
18:41:46,201 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap => {2765221448941953821={-5650150279934172176=[Ljava.lang.Object;@37a9aa}, 4523587801893665884={-84153624240172225=[Ljava.lang.Object;@1a46cd2}}
18:41:46,203 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: javax.faces.request.charset => UTF-8
18:41:46,203 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,204 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,205 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,205 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,207 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,208 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,208 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,209 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,210 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,210 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,211 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,212 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,213 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,213 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,214 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,215 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,215 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,216 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,217 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,217 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,218 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,219 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,219 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,220 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,221 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,221 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,222 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,223 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,223 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,224 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,225 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,225 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,226 FINER [xx.yy.zz.SkipValidatorUtil] (http--0.0.0.0-8081-2) Validation will be continued? false
18:41:46,226 FINER [xx.yy.zz.SkipBeanValidator] (http--0.0.0.0-8081-2) Skipping standard validation
18:41:46,227 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) After Phase: PROCESS_VALIDATIONS 3 Session exist: true Request Path: null
18:41:46,228 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Before Phase: RENDER_RESPONSE 6 Session exist: true
18:41:46,229 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: com.sun.faces.renderkit.ServerSideStateHelper.LogicalViewMap => {2765221448941953821={-5650150279934172176=[Ljava.lang.Object;@37a9aa}, 4523587801893665884={-84153624240172225=[Ljava.lang.Object;@1a46cd2}}
18:41:46,230 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) Session: javax.faces.request.charset => UTF-8
18:41:46,239 FINER [xx.yy.zz.jsf.PhaseTracker] (http--0.0.0.0-8081-2) After Phase: RENDER_RESPONSE 6 Session exist: true Request Path: null
{noformat}
As you can see from the above, it did not go through the UPDATE_MODEL_VALUES phase and did not go through the INVOKE_APPLICATION phase. It went stragith through to RENDER_RESPONSE phase, as if ignoring the validators that I provided.
So my question are:
*) Does providing your own validators in faces-config.xml override the default validators provided by the JSF implementation ?
*) If yes, then what I am doing wrong above .. as I only call the superclass validate() method when I want to ?
*) If no, what is an alternative ?