/*
* Copyright 2017 OmniFaces
*
* 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 org.omnifaces.validator;
import java.util.Objects;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
/**
* <p>
* By default, JSF validators run on every request, regardless of whether the submitted value has changed or not. In
* case of validation against the DB on complex objects which are already stored in the model in a broader scope, such
* as the view scope, this may result in unnecessarily expensive service/DAO calls. In such case, you'd like to perform
* the expensive service/DAO call only when the submitted value is really changed as compared to the model value.
* <p>
* This validator offers you a template to do it transparently. To use it, just change your validators from:
* <pre>
* public class YourValidator implements Validator {
*
* public void validate(FacesContext context, UIComponent component, Object submittedValue) {
* // ...
* }
*
* }
* </pre>
* <p>to
* <pre>
* public class YourValidator extends ValueChangeValidator {
*
* public void validateChangedObject(FacesContext context, UIComponent component, Object submittedValue) {
* // ...
* }
*
* }
* </pre>
* So, essentially, just replace <code>implements Validator</code> by <code>extends ValueChangeValidator</code> and
* rename the method from <code>validate</code> to <code>validateChangedObject</code>.
*
* @author Juliano
* @author Bauke Scholtz
* @since 1.7
*/
public abstract class ValueChangeValidator implements Validator {
/**
* If the component is an instance of {@link EditableValueHolder} and its old object value is equal to the
* submitted value, then return immediately from the method and don't perform any validation. Otherwise, invoke
* {@link #validateChangedObject(FacesContext, UIComponent, Object)} which may in turn do the necessary possibly
* expensive DAO operations.
*/
@Override
public void validate(FacesContext context, UIComponent component, Object submittedValue) {
if (component instanceof EditableValueHolder) {
Object newValue = submittedValue;
Object oldValue = ((EditableValueHolder) component).getValue();
if (Objects.equals(newValue, oldValue)) {
return;
}
}
validateChangedObject(context, component, submittedValue);
}
/**
* Use this method instead of {@link #validate(FacesContext, UIComponent, Object)} if you intend to perform the
* validation only when the submitted value is really changed as compared to the model value.
* @param context The involved faces context.
* @param component The involved UI component.
* @param submittedValue The submitted value.
*/
public abstract void validateChangedObject(FacesContext context, UIComponent component, Object submittedValue);
}