First of all let's define our custom validator class
public class DateConsistencyValidator extends AbstractFormValidator {
private static final long serialVersionUID = -4661147385331769440L;
private String dateComponent1;
private String dateComponent2;
private final FormComponent[] components;
public DateConsistencyValidator(final String dateComponent1, final String dateComponent2) {
this.dateComponent1 = dateComponent1;
this.dateComponent2 = dateComponent2;
components = new FormComponent[0];
}
@Override
public void validate(final Form form) {
AjaxDateFieldPanel component1 = getField(form, AjaxDateFieldPanel.class, dateComponent1);
AjaxDateFieldPanel component2 = getField(form, AjaxDateFieldPanel.class, dateComponent2);
if (component1.getField().getConvertedInput() != null
&& component2.getField().getConvertedInput() != null
&& component1.getField().getConvertedInput().after(component2.getField().getConvertedInput())) {
Map vars = new HashMap<>();
vars.put("field1Name", component1.getName());
vars.put("field2Name", component2.getName());
// use the following line if you do not want to take message from properties file
// form.error("Value of field ${field1Name} is not equal to ${field2Name}", vars);
form.error(component1.getString("date.consistency.validationError"), vars);
}
}
@Override
public FormComponent[] getDependentFormComponents() {
return components;
}
protected > T getField(
final Form form,
final Class clazz,
final String name) {
T component = form.visitChildren(clazz,
new IVisitor() {
@Override
public void component(final T arg0, final IVisit arg1) {
if (name.equalsIgnoreCase(StringUtils.isBlank(arg0.getName())
? arg0.getField().getLabel().getObject()
: arg0.getName())) {
arg1.stop(arg0);
}
}
});
return component;
}
}
Then let's define a custom wizard builder class that uses the custom validator and extends default UserWizardBuilder provided by Syncope
public class UserWithValidationWizardBuilder extends UserWizardBuilder {
private static final long serialVersionUID = 1680007693565519842L;
public UserWithValidationWizardBuilder(
final List anyTypeClasses,
final UserFormLayoutInfo formLayoutInfo,
final PageReference pageRef) {
super(anyTypeClasses, formLayoutInfo, pageRef);
}
public UserWithValidationWizardBuilder(
final UserTO previousUserTO,
final UserTO userTO,
final List anyTypeClasses,
final UserFormLayoutInfo formLayoutInfo,
final PageReference pageRef) {
super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef);
}
@Override
protected WizardModel buildModelSteps(final AnyWrapper modelObject, final WizardModel wizardModel) {
super.buildModelSteps(modelObject, wizardModel);
if (formLayoutInfo.isPlainAttrs()) {
PlainAttrs plainAttrs = getWizardStep(PlainAttrs.class, wizardModel);
// add form validators
if (plainAttrs != null) {
plainAttrs.add(new DateConsistencyValidator("loginDate", "logoutDate"));
}
}
return wizardModel;
}
@SuppressWarnings("unchecked")
protected T getWizardStep(final Class clazz, final WizardModel wizardModel) {
for (WizardModel.ICondition condition : wizardModel.getConditions()) {
if (clazz.isInstance(condition)) {
return clazz.cast(condition);
}
}
return null;
}
}
Please notice the simplicity: in order to enable validation on two (or more, depends on validator implementation) you just need to add the following line:
plainAttrs.add(new DateConsistencyValidator("mydate1", "mydate2"));
mydate1 and mydate2 are the names of existing Syncope schemas and reference user attributes.
Moreover, in order to get the message from properties file (like shown in the example) add a property to the file referenced by the attribute panel, for example AbstractFieldPanel.properties, located under
console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/
The line should look like this:
date.consistency.validationError=${field1Name} shall not be after ${field2Name}
Disclaimer: The provided implementation is only a sample to check dates consistency (fail if mydate1 is after mydate2), you can define whatever form validator by overriding AbstractFormValidator class provided by Apache Wicket.
If you are using a project generated from archetype place the wizard builder class in
console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWithValidationWizardBuilder.jav
a and the custom validator(s) in
console/src/main/java/org/apache/syncope/client/console/wizards/validators/DateConsistencyValidator.java
Finally build, deploy and restart you application server hosting Syncope.
Login as admin to console and setup a new role, say adminWithValidation (see following image) from Configuration -> Administration -> Roles
Then edit layout of the role by clicking on the just created role and then on layout. Set formClass to
org.apache.syncope.client.console.wizards.any.UserWithValidationWizardBuilder
Assign this role to some existing user and then login with that user.
In the following image you can see and example of frontend dates validation in action.
N.B. The custom validator is invoked only if the editing user (logged one) has the role with custom layout, say role adminWithValidation for example.
Enjoy :)