Skip to main content

Custom Model Validation

Target audience: Developers

Overview

Process model validation allows for validating the model in Design (during modeling) and / or in Work (before deploying a process definition). This allows for developers to write custom complex validation for their own custom palette elements or for existing palette elements (e.g. enforcing that every User Task has a priority).

Flowable has built in process validation for the custom tasks it provides and for the existing one from Open Source. e.g. deploying a service task without an expression, delegate expression or class will lead to a validation error in Design and to a failure to deploy the model in Work.

Example Use Case

Assume that we want to enforce that every single User Task has a certain priority set. One way of doing this is by using Task Listeners and throwing an exception when the task is created. This means that the process will still be deployed, and you will only notice the problem during the runtime execution of the process. It would be better for the modelers to see this error as early as possible, e.g. in Design or when trying to publish to Work. A model with an error in its validation will not even be published, i.e. you cannot even start an instance of this model.

Writing your own custom validation logic

Writing custom validations has 2 concepts:

  • Creating a ValidatorSet - This is a set Validator(s) that would be executed for a BpmnModel
  • Creating Validator(s) - This is the actual logic where you are going to write your validation logic

As a first step we are going to create a new dependency module with the following dependency:

<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-process-validation</artifactId>
<scope>provided</scope>
</dependency>

This module will be shared with your Design and Work applications. Therefore, it is really important that you do not have any runtime dependencies in it.

The next steps will be to write the actual Java code. If we follow the pattern that is done for Flowable Open Source with its ValidatorSetFactory, we will start with our own CustomValidatorSetFactory.

e.g.

public class CustomValidatorSetFactory {

public ValidatorSet createCustomValidatorSet() {
ValidatorSet validatorSet = new ValidatorSet("custom-validation");

// Here we will register all our own custom validator
validatorSet.addValidator(new CustomUserTaskValidator());

return validatorSet;
}

}

Each Validator Set has a name that displays from where the error message is coming from. This name is used as a prefix for the translations of the error messages, which will be shown later.

The CustomUserTaskValidator looks like:

public class CustomUserTaskValidator extends ProcessLevelValidator {

@Override
protected void executeValidation(BpmnModel bpmnModel, Process process, List<ValidationError> errors) {
List<UserTask> userTasks = process.findFlowElementsOfType(UserTask.class);
for (UserTask userTask : userTasks) {
executeValidation(process, userTask, errors);
}

}

protected void executeValidation(Process process, UserTask userTask, List<ValidationError> errors) {
String priority = userTask.getPriority();
if (priority == null || priority.isEmpty()) {
addError(errors, "user-task-no-priority", process, userTask, "User task must have a priority");
}
}
}

The ProcessLevelValidator is a small internal class that can be used to iterate through the BpmnModel (an internal Java representation of a process definition) processes. In our validator we are going to create an error if a user task does not have the priority set. When adding the error the "user-task-no-priority" is the id of the problem in your validator set ("custom-validation") and "User task must have a priority" is the description of the problem. This information will be part of the error message when deploying to Flowable Work or when doing the Validation in Design

Exposing the custom validation to Design and Work

In order to expose the custom validation that we wrote to Design and Work we need to add the following bean to our 2 applications:

@Bean
public ValidatorSet customProcessValidation() {
return new CustomValidatorSetFactory().createCustomValidatorSet();
}

Once this bean is available in the Application Context of Design or Work it will be used to perform the validation.

Improving the Design validation message

It is possible to provide different message for the validation error in Design. For this purpose you need to add a translation properties file at the top of the jar with the following name <validator-set-name>-design-validation.properties. In our example it will be custom-validation-design-validation.properties.

In this file you can then set the translations for each of your validation errors. The format of the translation is <validator-set-name>.<problem-id>=<translation>.

e.g.

custom-validation.user-task-no-priority=Priority must be set for a User Task

Once we have everything wired together and run the validation in Design with a User Task without a priority we should see something like:

Custom Validation Error in Design