
org.nuiton.validator.bean.AbstractValidator Maven / Gradle / Ivy
package org.nuiton.validator.bean;
/*
* #%L
* Validation :: API
* %%
* Copyright (C) 2021 - 2024 Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import com.google.common.base.Preconditions;
import org.nuiton.validator.NuitonValidator;
import org.nuiton.validator.NuitonValidatorModel;
import org.nuiton.validator.NuitonValidatorProvider;
import org.nuiton.validator.NuitonValidatorScope;
import javax.swing.event.EventListenerList;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Objects;
import java.util.Set;
/**
* TODO
*
* @param type of bean to validate
* @author Tony Chemit - [email protected]
* @since 2.5.2
*/
public abstract class AbstractValidator {
/**
* Name of the bounded property {@code context}.
*
* @see #getContext()
* @see #setContext(String)
*/
public static final String CONTEXT_PROPERTY = "context";
/**
* Name of the bounded property {@code scopes}.
*
* @see #getScopes()
* @see #setScopes(NuitonValidatorScope...)
*/
public static final String SCOPES_PROPERTY = "scopes";
/**
* Name of the bounded property {@link #valid}.
*
* @see #valid
* @see #isValid()
* @see #setValid(boolean)
*/
public static final String VALID_PROPERTY = "valid";
/**
* Name of the bounded property {@link #changed}.
*
* @see #changed
* @see #isChanged()
* @see #setChanged(boolean)
*/
public static final String CHANGED_PROPERTY = "changed";
/**
* Listener that listens on bean modification.
*/
protected final PropertyChangeListener l;
/**
* delegate property change support
*/
protected final PropertyChangeSupport pcs;
/**
* A list of event listeners for this validators
*/
protected final EventListenerList listenerList = new EventListenerList();
/**
* The provider of delegate validators.
*
* It will also produce validator model.
*
* @see NuitonValidatorProvider
*/
protected final NuitonValidatorProvider validatorProvider;
/**
* State to indicate that validator has changed since the last time bean was set.
*/
protected boolean changed;
/**
* State of the validator (is true if no errors of error scope is found).
*/
protected boolean valid = true;
/**
* State to know if the validator can be used (we keep this state for
* performance reasons : do not want to compute this value each time a
* validation is asked...).
*/
protected boolean canValidate = true;
protected AbstractValidator(NuitonValidatorProvider validatorProvider,
Class beanClass) {
// check if given bean class is Javabean compiliant
boolean javaBeanCompiliant = BeanUtil.isJavaBeanCompiliant(beanClass);
Preconditions.checkState(
javaBeanCompiliant,
beanClass.getName() + " is not JavaBean compiliant (" +
BeanUtil.ADD_PROPERTY_CHANGE_LISTENER + ", or " +
BeanUtil.REMOVE_PROPERTY_CHANGE_LISTENER +
" method not found).");
this.validatorProvider = validatorProvider;
pcs = new PropertyChangeSupport(this);
l = evt -> {
@SuppressWarnings("unchecked") O bean = (O) evt.getSource();
// the bean has changed, replay validation
doValidate(bean);
};
}
/**
* Obtain the {@link #changed} property value.
*
* Returns {@code true} if bean was modified since last
* time a bean was attached.
*
* @return {@code true} if bean was modified since last attachement of
* a bean.
*/
public boolean isChanged() {
return changed;
}
/**
* To force the value of the property {@link #changed}.
*
* @param changed flag to force reset of property {@link #changed}
*/
public void setChanged(boolean changed) {
this.changed = changed;
// force the property to be fired (never pass the older value)
firePropertyChange(CHANGED_PROPERTY, null, changed);
}
public boolean isCanValidate() {
return canValidate;
}
public void setCanValidate(boolean canValidate) {
this.canValidate = canValidate;
}
/**
* Obtain the {@link #valid} property value.
*
* @return {@code true} if attached bean is valid (no error or fatal messages)
*/
public boolean isValid() {
return valid;
}
/**
* Change the value of the {@link #valid} property.
*
* @param valid the new value of the property
*/
public void setValid(boolean valid) {
this.valid = valid;
// force the property to be fired (never pass the older value)
firePropertyChange(VALID_PROPERTY, null, valid);
}
public String getContext() {
return getModel().getContext();
}
public void setContext(String context) {
String oldContext = getContext();
if (Objects.equals(context, oldContext)) {
// same context do nothing
return;
}
NuitonValidatorModel model = getModel();
// compute the new validator model
NuitonValidatorScope[] scopes = model.getScopes().toArray(new NuitonValidatorScope[0]);
rebuildDelegateValidator(
model.getType(),
context,
scopes
);
firePropertyChange(CONTEXT_PROPERTY,
oldContext,
context
);
}
public Set getScopes() {
return getModel().getScopes();
}
public void setScopes(NuitonValidatorScope... scopes) {
Set oldScopes = getScopes();
rebuildDelegateValidator(
getModel().getType(),
getModel().getContext(),
scopes
);
firePropertyChange(SCOPES_PROPERTY,
oldScopes,
scopes
);
}
public Set getEffectiveScopes() {
return getDelegate().getEffectiveScopes();
}
public Set getEffectiveFields() {
return getDelegate().getEffectiveFields();
}
public Set getEffectiveFields(NuitonValidatorScope scope) {
return getDelegate().getEffectiveFields(scope);
}
public abstract void doValidate();
public abstract boolean hasFatalErrors();
public abstract boolean hasErrors();
public abstract boolean hasWarnings();
public abstract boolean hasInfos();
public abstract boolean isValid(String fieldName);
public abstract NuitonValidatorScope getHighestScope(String field);
protected abstract void doValidate(O bean);
protected abstract NuitonValidator getDelegate();
protected abstract void rebuildDelegateValidator(Class beanType,
String context,
NuitonValidatorScope... scopes);
public Class getType() {
return getModel().getType();
}
/**
* Test a the validator contains the field given his name
*
* @param fieldName the name of the searched field
* @return true
if validator contaisn this field,
* false
otherwise
*/
public boolean containsField(String fieldName) {
Set effectiveFields = getDelegate().getEffectiveFields();
return effectiveFields.contains(fieldName);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
pcs.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
pcs.removePropertyChangeListener(propertyName, listener);
}
public void firePropertyChange(String propertyName,
Object oldValue,
Object newValue) {
pcs.firePropertyChange(propertyName, oldValue, newValue);
}
protected NuitonValidatorModel getModel() {
return getDelegate().getModel();
}
}