Tip: Validation with a MultiValidator
February 27, 2009 | 3 min ReadIn the last blog entry regarding databinding, we learned how to create a custom observable for a DateTime widget. Starting with Eclipse 3.5 there is a new approach to creating custom observables as described by Matthew Hall in the comments to that post. Which ever way you choose, we will now use the observable to showcase another cool databinding feature: Crossvalidation. Crossvalidation was introduced with Eclipse 3.4 and describes the process of validating one IObservable based on the value or state of another IObservable. A classic example is the input of a date ranges where the start of the period can not be after the end of the period.
As we can see on the screenshot above, the status message informs us of a violated validation constrain. So, how is such kind of crosscutting validation achieved? First of we need some kind of model, to hold the start and end value. Next we need the two DateTime widgets and the corresponding DateTimeObservableValue. The observables can than be tied to the bean model, holding the start and end values. In order to create a crosscutting validation for the dates, we introduce a custom PeriodValidator extending a MultiValidator, which is in fact an implementation of a ValidationStatusProvider.The MultiValidator lets us implement a validate() method, returning an IStatus corresponding to our validation results. Since we are implicitly implementing a ValidationStatusProvider, the state of our validation can be bound to any party interested in the validation result. Here is the implementation of the PeriodValidator, comparing the start and end date (ignore the shortcomings of the Date class):
public class PeriodValidator extends MultiValidator {
private final IObservableValue start; private final IObservableValue end;
public PeriodValidator(final IObservableValue start, final IObservableValue end) { this.start = start; this.end = end; }
@Override protected IStatus validate() { Date startDate = (Date) this.start.getValue(); Date endDate = (Date) this.end.getValue(); IStatus status = ValidationStatus.ok();
if ((this.start != null) && (this.end != null)) { if (startDate.after(endDate)) { status = ValidationStatus.error(”The start date has to be before the end date.”); } } return status; } } ```
As we can see, there is not much magic going on in the _PeriodValidator_. Lets have a look at the broader context, in which this _MultiValidator_ is applied. The following code demonstrates the overall setup of the databinding. Note how the validation status (wrapped in an _IObservableValue_) is obtained from the _PeriodValidator_ and bound to the status _Text_ widget.
```java private void createDatabinding() {
DateTimeObservableValue startObservable = new DateTimeObservableValue(this.dateTimeStart); DateTimeObservableValue endObservable = new DateTimeObservableValue(this.dateTimeEnd); DataBindingContext context = new DataBindingContext();
// bind start and end UpdateValueStrategy modelToTarget = new UpdateValueStrategy( UpdateValueStrategy.POLICY\_UPDATE); UpdateValueStrategy targetToModel = new UpdateValueStrategy( UpdateValueStrategy.POLICY\_UPDATE); context.bindValue( startObservable, BeansObservables.observeValue(this.period,Period.PROP\_START), targetToModel, modelToTarget);
context.bindValue(endObservable, BeansObservables.observeValue(this.period, Period.PROP\_END), targetToModel, modelToTarget);
// bind status PeriodValidator periodValidator = new PeriodValidator(startObservable, endObservable); modelToTarget = new UpdateValueStrategy(UpdateValueStrategy.POLICY\_UPDATE); modelToTarget.setConverter(new Converter(IStatus.class, String.class) {
public Object convert(final Object arg) {
if (arg instanceof IStatus) { IStatus status = (IStatus) arg; return status.getMessage(); }
return null; } });
targetToModel = new UpdateValueStrategy(UpdateValueStrategy.POLICY\_UPDATE); context.bindValue( SWTObservables.observeText(this.status), periodValidator.getValidationStatus(), targetToModel, modelToTarget); }
The validation status of the period validator is updated everytime any of the DateTime widgets is changed. In turn the validation message is updated to reflect the validation state.
You can download the the entire project containing the sample snippets from our website.
Also note that you will need to adjust the elements on the classpath. See the .project file for the required libs.
I hope you found these hints valuable and am looking forward to your comments and suggestions.