Slice 4.0 has a simple validation mechanism which allows you to check if a model meets certain requirements or, in other words, is valid. Thanks to validation tag, a component whose model is not valid may not be displayed on a page.
Basic interfaces
The validation mechanism is based on two interfaces:
Validatable
If a class should be a subject to validation it should implement com.cognifide.slice.validation.api.Validatable
. The interface introduces only one method: validate
, which takes one argument: com.cognifide.slice.validation.api.ValidationResultBuilder
. The argument allows you to define a validation messages of different levels. The levels include:
- error
- warning
- information
If at least one message has been added, the object is considered invalid. If there is no message, the object is considered valid.
An example usage of the interface is shown in the following listing. If the text property, mapped from the resource, is blank, the model is invalid.
Code Block |
---|
import org.apache.commons.lang.StringUtils;
import com.cognifide.slice.mapper.annotation.JcrProperty;
import com.cognifide.slice.mapper.annotation.SliceResource;
import com.cognifide.slice.validation.api.Validatable;
import com.cognifide.slice.validation.api.ValidationResultBuilder;
@SliceResource
public class TextModel implements Validatable {
@JcrProperty
private String text;
@Override
public void validate(ValidationResultBuilder result) {
if (StringUtils.isBlank(text)) {
result.addErrorMessage("Text cannot be empty");
}
}
public String getText() {
return text;
}
} |
Validator
The actual validation of an object is performed by com.cognifide.slice.validation.api.Validator
interface. It defines one method: validate
, which takes Validatable
object as an argument. It returns ValidationResult
as a result of validation. ValidationResult
can be used for reading a result of validation and validation messages.
Slice's validation module provides a default implementation of the interface which can be used (injected) in your models to perform validation of objects of different types. Take a look at the example below where the model created by ModelProvider
is validated before use.
Code Block |
---|
import com.cognifide.slice.api.model.InitializableModel;
import com.cognifide.slice.api.provider.ModelProvider;
import com.cognifide.slice.mapper.annotation.JcrProperty;
import com.cognifide.slice.mapper.annotation.SliceResource;
import com.cognifide.slice.validation.api.Validator;
import com.cognifide.app.components.configuration.image.ImageConfigurationModel;
import com.google.inject.Inject;
@SliceResource
public class ImageModel implements InitializableModel {
@JcrProperty
private String configPath;
private int size;
private final ModelProvider modelProvider;
private final Validator validator;
@Inject
public ImageModel(final ModelProvider modelProvider, final Validator validator) {
this.modelProvider = modelProvider;
this.validator = validator;
}
@Override
public void afterCreated() {
ImageConfigurationModel configurationModel = modelProvider.get(ImageConfigurationModel.class, configPath);
if (validator.validate(configurationModel).isValid()) {
size = configurationModel.getDefaultSize();
} else {
...
}
}
...
} |
Validation tag
To render a validation message to an end-user (author), you need to use a dedicated JSP tag - validate tag defined in the http://cognifide.com/jsp/slice/validation taglib. The example below shows an simple usage of it.
Code Block | ||||
---|---|---|---|---|
| ||||
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"
%><%@include file="/apps/myapp/core/global.jsp"
%><slice:lookup var="model" type="<%=com.cognifide.myapp.components.richtext.TextModel.class%>"/>
<sv:validate object="${model}" displayErrors="${wcmMode.edit}">
${model.text}
</sv:validate> |
The taglib is registered under sv
prefix. The TextModel
object (obtained using <slice:lookup>
tag) is validated in line 4. If the object is valid, the body of the validation tag will be rendered. Otherwise, error message will be output in the following format:
Code Block | ||
---|---|---|
| ||
<div class="validationMessages">
<div class="title">
title <!-- only if defined -->
</div>
<ul class="errorMessages"> <!-- if error-level messages available -->
<li>Text cannot be empty</li>
<!-- stack trace --> <!-- if stack trace for the message is available, it is printed in HTML comment -->
</ul>
<ul class="warningMessages"> <!-- if warning-level messages available -->
<li>Some warning</li>
<!-- stack trace --> <!-- if stack trace for the message is available, it is printed in HTML comment -->
</ul>
<ul class="informationMessages"> <!-- if information-level messages available -->
<li>Some information</li>
<!-- stack trace --> <!-- if stack trace for the message is available, it is printed in HTML comment -->
</ul>
</div>
<div style="clear:both;font-size:1px"> </div> |
Such format allows you to style them appropriately.
Note | ||
---|---|---|
| ||
It should be noted that validation messages should not be displayed in publish, they should be displayed only in edit mode. To achieve this, displayErrors attribute should be set to true only in edit mode (see line 4 in above example) |
Sum up of attributes:
Attribute | Description | Required? |
---|---|---|
object | object that needs to be validated | |
title | Heading of validation messages displayed to authors, "Validation messages:" by default | |
displayErrors | Defines if error messages should be displayed or not. The boolean value which should be based on CQ mode | |
var | Variable where validation result will be stored for further use | |
appName | Application name (optional), allows specifying the injector name |
Blank values approach
There is a special case of validation where we'd like to inform authors that the component has not been edited yet and it needs author's attention. This is especially useful when an author drags and drops a new component onto paragraph system, and the component needs to render itself. Usually, such component cannot pass validation without being edited first what's resulting in displaying error messages. This can be, in turn, misleading for authors.
Therefore, the blank values approach has been introduced. It allows a component to render its predicted output, meaning how the component will look like after it is initially edited.
The blank value approach is based on validate
tag. A component implementing blank values approach behaves as follows:
- If a Java model is blank and
displaysErrors
is set totrue
(should be only in edit mode), the body of validation tag is not rendered - blank value is rendered instead. Blank value is either a piece of HTML or a placeholder image. - If a Java model is blank and
displaysErrors
is set tofalse
(should be in mode other than edit), the body of validation tag does render nothing - If a Java model is not blank, the validation of the model is performed and, depending on validation result, either body of validation tag or error messages are rendered.
To display a blank value, the component must meet the following:
It must define its blank state. This can be achieved using Validatable
interface by calling the setBlank
method on ValidationResultBuilder
object. E.g.:
Code Block |
---|
import org.apache.commons.lang.StringUtils;
import com.cognifide.slice.mapper.annotation.JcrProperty;
import com.cognifide.slice.mapper.annotation.SliceResource;
import com.cognifide.slice.validation.api.Validatable;
import com.cognifide.slice.validation.api.ValidationResultBuilder;
@SliceResource
public class TextModel implements Validatable {
@JcrProperty
private String text;
@Override
public void validate(ValidationResultBuilder result) {
if (StringUtils.isBlank(text)) {
result.setBlank(true);
}
}
public String getText() {
return text;
}
} |
...
It should provide the blank value output. It can be done easily by putting an HTML file called blank.html in the component folder. The content of this file will be rendered when the component's model is blank. The content is a pure HTML, is should not contain any server-side scripts. Example blank.html file for a richtext component may look as follows:
Code Block | ||
---|---|---|
| ||
<div class="init richtext">
<p>This is a richtext</p>
</div> |
...
As a result of cleaning up Slice from various utility functionality we decided to remove the whole validation mechanism in Slice 4.0.
If you would like to use this mechanism with Slice 4.0, feel free to take classes responsible for that from Slice 3.2.0 source code: https://github.com/Cognifide/Slice/tree/3.2.0 and create your own validation library. The code from version 3.2 is fully compatible with Slice 4.0.
More details on how to use validation you can find in Slice 3.2 documentation.