# Holon Vaadin UI

version 5.0.1

Copyright © 2016-2017

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

## 1. Introduction

The Holon Vaadin module represents the platform support for the Vaadin web applications framework, focusing on the user interface components and data binding features.

This module provides integration with the platform foundation architecture, such as the `Property` model and the `Datastore` API, the authentication, authorization and localization support.

The view navigation system allows to create web applications focusing on the application functions, which can be represented by virtual pages, relying on a robust navigation architecture, with parameters and view lifecycle hooks support.

Furthermore, a complete set of fluent builders is available, to build web application UIs quickly and easily.

## 2. Obtaining the artifacts

The Holon Platform uses Maven for projects build and configuration. All the platform artifacts are published in the Maven Central Repository, so there is no need to explicitly declare additional repositories in your project `pom` file.

At the top of each section of this documentation you will find the Maven coordinates (group id, artifact id and version) to obtain the artifact(s) as a dependency for your project.

A BOM (Bill Of Materials) `pom` is provided to import the available dependencies for a specific version in your projects. The Maven coordinates for the core BOM are the following:

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-vaadin-bom</artifactId>
    <version>5.0.1</version>

The BOM can be imported in a Maven project in the following way:

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>com.holon-platform.vaadin</groupId>
          <artifactId>holon-vaadin-bom</artifactId>
          <version>5.0.1</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>

### 2.1. Using the Platform BOM

The Holon Platform provides an overall Maven BOM (Bill of Materials) to easily obtain all the available platform artifacts.

See Obtain the platform artifacts for details.

## 3. Vaadin integration

The `holon-vaadin` artifact is the main entry point to use the Holon platform Vaadin integration.

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-vaadin</artifactId>
    <version>5.0.1</version>

## 4. Component builders

A complete set of fluent builders is available to create and configure the most common Vaadin standard components and the ones provided by the Holon platform Vaadin integration module.

| See UI Components for a list of the additional components made available by the Holon platform Vaadin integration module.

All the builders can be obtained by using the Components interface, which is organized in sub-interfaces by components kind.

Table 1. Components builders structure
Sub-interface | Provides
--- | ---
[NONE] | A set of configure(*) methods to setup existing standard component instances and a set of methods to obtain the fluent builders for standard Vaadin components, such as `Label`, `Button`, and standard layout components.
input | Builders for different data type `Input` components, including selection components. Furthermore, it provides builder to create input forms.
view | Builders for `ViewComponent` components and view forms.
listing | Builders for components which represent a list of items.

| For each UI displayed text of a component (for example, the component caption or description), the builders provide the opportunity to set a localizable text, using a `Localizable` object or directly providing the message code and the default message of the localizable text. In order for the localization to work, a `LocalizationContext` must be available as a context resource. See the Internationalization documentation for further information.

## 5. UI Components

The Vaadin module provides a set of components which extend or decorates the standard components set. The available components are described below.

### 5.1. Input

The Input interface represents a component that has a user-editable value, which can be read and setted using the methods provided by the The ValueHolder super interface.

Input components support the read-only (to prevent the user from changing the value) and required (to show a suitable indicator along with the field) modes.

Input components supports `ValueChangeListener` registration to listen to input value changes.

    Input<String> stringInput = Components.input.string().caption("String input").inputPrompt("Value here")
        .maxLength(100).styleName("mystyle").build(); (1)

    stringInput.setValue("test"); (2)
    String value = stringInput.getValue(); (3)

    stringInput.addValueChangeListener(e -> System.out.println("Value: " + e.getValue())); (4)

1 | Create and configure a `String` value type `Input` field.
2 | Set a value
3 | Get the value
4 | Add a `ValueChangeListener`

The concrete Vaadin `Component`, which represents the UI input element, can be obtained through the `getComponent()` method.

    Input<LocalDate> dateInput = Components.input.localDate().caption("Date input").lenient(true).build(); (1)

    Component inputComponent = dateInput.getComponent(); (2)

1 | Create and configure a `LocalDate` value type `Input` field.
2 | Get the input `Component`, which can be used to display the input field in UI.

An `Input` component can be obtained from a standard Vaadin `HasValue` component using the `from(…​)` static method.

    Input<String> stringInput = Input.from(new TextField());

Another way to obtain a standard Vaadin `HasValue` component from an input component is to use the `asField()` input builder method.

    Field<Locale> localeField = Components.input.singleSelect(Locale.class).items(Locale.US, Locale.CANADA)
        .caption("Select Locale").fullWidth().withValue(Locale.US).asField(); (1)

1 | Create select field using `Locale` data type and obtain it as `Field`, i.e. as a standard `HasValue` component.

### 5.2. ValidatableInput

The ValidatableInput interface represents an `Input` component which supports value validation using the standard Holon platform `Validator` interface.

Value validation can be triggered each time the input value changes, using `setValidateOnValueChange` method.

A ValidationStatusHandler can be used to control how the validation errors are notified to the user, listening to validation status change events.

By default, the standard Vaadin component error notification is used.

    Input<String> stringInput = Components.input.string().build();
    ValidatableInput<String> validatableInput = ValidatableInput.from(stringInput); (1)

    validatableInput.addValidator(Validator.email()); (2)
    validatableInput.addValidator(Validator.max(100)); (3)

    validatableInput.setValidationStatusHandler(e -> { (4)
      if (e.isInvalid()) {
        Notification.show(e.getErrorMessage(), Type.ERROR_MESSAGE);
      }
    });

    validatableInput.validate(); (5)

    validatableInput.setValidateOnValueChange(true); (6)

1 | Create a `ValidatableInput` from a String input
2 | Add a validator to check the input value is a valid e-mail address
3 | Add a validator to check the input value is maximum 100 characters long
4 | Set validation status handler which shows a notification when the input in invalid
5 | Perform the input value validation
6 | Triggers validation when input value changes

A `ValidatableInput` can be obtained from an existing `Input` or `HasValue` component instance or by using the appropriate builder.

    ValidatableInput<String> validatableInput = ValidatableInput.from(Components.input.string().build()); (1)

    validatableInput = ValidatableInput.from(new TextField()); (2)

    validatableInput = Components.input.string().validatable() (3)
        .required("Value is required") (4)
        .withValidator(Validator.max(100)).build(); (5)

1 | Create a `ValidatableInput` from a String `Input`
2 | Create a `ValidatableInput` from a String type `HasValue` component
3 | Create a `ValidatableInput` using the input builder
4 | Add a default required (the input is not empty) validator using the provided error message
5 | Add a standard validator

### 5.3. Selectable Input

When the Input values must be selected from a specific set, a selectable Input type can be used. Two selectable Input types are available:

- The SingleSelect Input, in which at most one item can be selected at a time;

- The MultiSelect Input, in which multiple items can be selected at the same time.

Both selectable Input types extends the Selectable interface, which provides methods to check if some item is selected, obtain the selected item/s and change the current selection. Furthermore, a `SelectionListener` can be registered to listen to selection changes.

SingleSelect example

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class).caption("Single select")
        .build(); (1)

    singleSelect.setValue(new TestData(1)); (2)
    singleSelect.select(new TestData(1)); (3)

    singleSelect.clear(); (4)
    singleSelect.deselectAll(); (5)

    boolean selected = singleSelect.isSelected(new TestData(1)); (6)

    singleSelect.addSelectionListener(
        s -> s.getFirstSelectedItem().ifPresent(i -> Notification.show("Selected: " + i.getId()))); (7)

1 | Create a `SingleSelect` Input using the `TestData` class as selection item type
2 | Select a value using the default `setValue()` Input method
3 | Select a value using `select()` method
4 | Deselect the value using the default `clear()` Input method
5 | Deselect the value using the `deselectAll()` method
6 | Check whether a value is selected
7 | Add a selection listener

MultiSelect example

    MultiSelect<TestData> multiSelect = Components.input.multiSelect(TestData.class).caption("Multi select")
        .build(); (1)

    Set<TestData> values = new HashSet<>();
    values.add(new TestData(1));
    values.add(new TestData(2));

    multiSelect.setValue(values); (2)
    multiSelect.select(new TestData(3)); (3)

    multiSelect.deselect(new TestData(3)); (4)

    multiSelect.clear(); (5)
    multiSelect.deselectAll(); (6)

    boolean selected = multiSelect.isSelected(new TestData(1)); (7)

    multiSelect.addSelectionListener(s -> Notification.show(s.getAllSelectedItems().stream()
        .map(i -> String.valueOf(i.getId())).collect(Collectors.joining(";", "Selected: ", "")))); (8)

1 | Create a `MultiSelect` Input using the `TestData` class as selection item type
2 | Select a set of values using the default `setValue()` Input method
3 | Add a value to current selection using the `select()` method
4 | Remove a value from current selection
5 | Deselect the value using the default `clear()` Input method
6 | Deselect the value using the `deselectAll()` method
7 | Check whether a value is selected
8 | Add a selection listener

#### 5.3.1. Rendering mode

The visual aspect of the selectable Input can be configured using the `RenderingMode` enumeration. According to the rendering mode, a suitable UI component will be used to implement the Input.

| The default rendering modes are `SELECT` for `SingleSelect` inputs and `OPTIONS` for `MultiSelect` inputs.

Rendering mode | SingleSelect UI component | MultiSelect UI component
--- | --- | ---
NATIVE_SELECT | `com.vaadin.ui.NativeSelect` | not supported
SELECT | `com.vaadin.ui.ComboBox` | `com.vaadin.ui.ListSelect`
OPTIONS | `com.vaadin.ui.CheckBoxGroup` | `com.vaadin.ui.RadioButtonGroup`

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class, RenderingMode.OPTIONS)
        .build(); (1)

    MultiSelect<TestData> multiSelect = Components.input.multiSelect(TestData.class, RenderingMode.SELECT).build(); (2)

1 | Create a `SingleSelect` using the OPTIONS rendering mode: a CheckBox group UI component will be used
2 | Create a `MultiSelect` using the SELECT rendering mode: a ListSelect UI component will be used

#### 5.3.2. Selection items data source

The data source of the available items for a selectable input can be configured in the following ways:

- Using a fixed set of items, which can be provided using the `addItem(…​)` or `items(…​)` methods of the select input builder;

- Using a Holon platform `ItemDataProvider` data provider;

- Using a standard Vaadin `DataProvider`.

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class)
        .items(new TestData(1), new TestData(2)).build(); (1)

    singleSelect = Components.input.singleSelect(TestData.class)
        .dataSource(ItemDataProvider.create(q -> 2, (q, o, l) -> Stream.of(new TestData(1), new TestData(2))))
        .build(); (2)

    singleSelect = Components.input.singleSelect(TestData.class)
        .dataSource(DataProvider.ofItems(new TestData(1), new TestData(2))).build(); (3)

1 | Create a select input using an explicitly provided items set
2 | Create a select input using a Holon platform `ItemDataProvider`
3 | Create a select input using a Vaadin `DataProvider`

#### 5.3.3. Item captions and icons

The selectable input builders allow to explicitly set the selection item captions and icons. As for the items caption, the Holon platform localization architecture is supported, and the builders provide methods to specify the caption using a `Localizable` or a message code.

| In order for the localization to work, a `LocalizationContext` must be available as a context resource. See the Internationalization documentation for further information.

    final TestData ONE = new TestData(1);
    final TestData TWO = new TestData(2);

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class).items(ONE, TWO)
        .itemCaption(ONE, "One") (1)
        .itemCaption(ONE, "One", "caption-one-message-code") (2)
        .itemIcon(ONE, VaadinIcons.STAR) (3)
        .build();

1 | Set the item caption for the `ONE` item
2 | Set the localizable item caption for the `ONE` item, providing a default caption and a translation message code
3 | Set the item icon for the `ONE` item

Furthermore, the `ItemCaptionGenerator` and the `ItemIconGenerator` interfaces can be used to provide custom selection items captions and icons. By default, the item caption is obtained using the `toString()` method of the item class and no icon is displayed.

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class)
        .items(new TestData(1), new TestData(2)) // set the items
        .itemCaptionGenerator(i -> i.getDescription()) (1)
        .itemIconGenerator(i -> i.getId() == 1 ? VaadinIcons.STAR : VaadinIcons.STAR_O) (2)
        .build();

1 | Set an item caption generator which provides the item description as item caption
2 | Set an item icon generator

#### 5.3.4. SingleSelect caption filter

For `SingleSelect` inputs using SELECT rendering mode, the UI component allows the user to type a filtering text to search for a selection item, and such filter by default is referred to item captions.

When using a fixed item set, the in-memory caption filter can be customized using the `filteringMode(…​)` builder method.

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class)
        .items(new TestData(1), new TestData(2)) // set the items
        .filteringMode(
            (itemCaption, filterText) -> itemCaption.toLowerCase().startsWith(filterText.toLowerCase())) (1)
        .build();

When using a `ItemDataProvider` or a Vaadin `DataProvider`, an overloaded form of the `dataSource(…​)` method can be used, which accept as second parameter a function to provide a suitable query filter using the current user filtering text.

    final TestData ONE = new TestData(1);
    final TestData TWO = new TestData(2);

    SingleSelect<TestData> singleSelect = Components.input.singleSelect(TestData.class).dataSource(
        ItemDataProvider.create(q -> 2, (q, o, l) -> Stream.of(ONE, TWO)),
        filterText -> QueryFilter.startsWith(ConstantExpression.create("description"), filterText, true))
        .build();

#### 5.3.5. Using the `Property` model with selectable Inputs

The Holon platform `Property` model is fully supported by the selectable input builder, which allows to create selectable inputs using `PropertyBox` type items and a specific `Property` as selection property (typically, the property which acts as item id).

The selection data type will be the same as the selection property type.

The simplest way to configure a `Property` based selectable input, is by using a `Datastore`.

| See the Property documentation for further information about the Holon platform `Property` model.

    Datastore datastore = obtainDatastore();

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    SingleSelect<Long> singleSelect = Components.input.singleSelect(ID) (1)
        .dataSource(datastore, DataTarget.named("testData"), PropertySet.of(ID, DESCRIPTION)) (2)
        .itemCaptionGenerator(propertyBox -> propertyBox.getValue(DESCRIPTION)) (3)
        .build();

    singleSelect.setValue(Long.valueOf(1)); (4)
    Long selectedId = singleSelect.getValue(); (5)

    singleSelect.refresh(); (6)

1 | Create a `SingleSelect` using the `ID` property as selection property
2 | Set the select data source using a `Datastore`, specifying the `DataTarget` and the set of property to use as query projection
3 | Set an item caption generator which provides the value of the `DESCRIPTION` property as item caption
4 | Set the selected value, which will be of type `Long`, consistent with the `ID` selection property
5 | Get the selected value, which will be of type `Long`, consistent with the `ID` selection property
6 | Refresh the selection items, querying the `Datastore`

One or more `QueryConfigurationProvider` can be used to control the Datastore query configuration, providing additional filters and/or sorts.

    Datastore datastore = obtainDatastore();

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    SingleSelect<Long> singleSelect = Components.input.singleSelect(ID)
        .dataSource(datastore, DataTarget.named("testData"), PropertySet.of(ID, DESCRIPTION), // Datastore
            () -> ID.gt(0L)) (1)
        .itemCaptionGenerator(propertyBox -> propertyBox.getValue(DESCRIPTION)).build();

1 | Set a `QueryConfigurationProvider` which provides a `QueryFilter` to select only the items with the `ID` property that is greater than 0

### 5.4. Grouping Inputs

The PropertyInputGroup component allows to group and manage a set of `Input` fields, relying on the `Property` model and using `PropertyBox` objects to collect, set and provide the Input values.

| See the Property documentation for further information about the Holon platform `Property` model.

A `PropertyInputGroup` is bound to a set of properties, and for each property an `Input` field is made available to set and get the property value. Each property has to be bound to an `Input` field with a consistent value type.

The property values are setted and obtained using the `PropertyBox` data container, with the same property set of the input group.

The property values are automatically updated in the current `PropertyBox` according to any user modification made through the input’s UI components.

The property input group supports `ValueChangeListener` registration to be notified when the group `PropertyBox` value changes.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyInputGroup group = Components.input.propertyGroup().properties(PROPERTIES) (1)
        .bind(ID, Components.input.number(Long.class).build()) (2)
        .bind(DESCRIPTION, Components.input.string().maxLength(100).build()) (3)
        .build();

    group.setValue(PropertyBox.builder(PROPERTIES).set(ID, 1L).set(DESCRIPTION, "TestDescription").build()); (4)

    PropertyBox value = group.getValue(); (5)

    group.addValueChangeListener(e -> { (6)
      PropertyBox changedValue = e.getValue();
    });

1 | Create a `PropertyInputGroup` using the `PROPERTIES` property set
2 | Bind the `ID` property to a `Long` type Input field
3 | Bind the `DESCRIPTION` property to a `String` type Input field
4 | Set the property values using a `PropertyBox` instance
5 | Get the property values as a `PropertyBox` instance
6 | Add a group `ValueChangeListener`

The default Holon platform `PropertyRenderer` architecture can be used to automatically generate a suitable Input component for a `Property`, according to its type.

The `bind(…​)` builder method can therefore be used to override the default property input generation only when a custom `Input` type is required.

| See Property renderers and presenters for further information about property renderers.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyInputGroup group = Components.input.propertyGroup().properties(PROPERTIES).build(); (1)

1 | The property `Input` fields are automatically generated using the available `PropertyRenderer` from the default registry

#### 5.4.1. Read-only properties

A property can be setted as read-only, to prevent the modification of its value. When a property is read-only, the `Input` component will be in read-only mode too, preventing the user from changing the value.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyInputGroup group = Components.input.propertyGroup().properties(PROPERTIES) //
        .readOnly(ID) (1)
        .build();

1 | The `ID` property is setted as read-only, preventing the user from changing the property value

#### 5.4.2. Hidden properties

A property can be setted as hidden. When a property is hidden, it is part of the group property set and its value will be preserved in the `PropertyBox` instances, but no `Input` component will be generated and bound to the property itself, so its value will never be visible on the user interface.

The `hidden(Property property)` method of the group builder can be used to set a property as hidden.

#### 5.4.3. Default property values

A default value can be provided for a property. If available, the default value will be used as property value when the corresponding Input component is empty (i.e. has no value).

The `defaultValue(Property<T> property, DefaultValueProvider<T> defaultValueProvider)` method of the group builder can be used to set a default value for a property.

### 5.5. Input group validation

A `PropertyInputGroup` support both property value and group value validation, using both standard Holon platform `Validator` and Vaadin validators.

A set of `required(…​)` group builder methods are provided to add a required validator to a property (i.e. a validator that check the value is not null or empty) and to show the required indicator symbol along with the property input component.

When a validator in bound to the overall input group, the value to validate will be represented by the `PropertyBox` which contains all the current property values.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyInputGroup group = Components.input.propertyGroup().properties(PROPERTIES) //
        .withValidator(DESCRIPTION, Validator.max(100)) (1)
        .required(ID) (2)
        .required(ID, "The ID value is required") (3)
        .withValidator(Validator.create(propertyBox -> propertyBox.getValue(ID) > 0,
            "The ID value must be greater than 0")) (4)
        .build();

1 | Add a validator bound to the `DESCRIPTION` property to check that the value size is not greater than 100 characters
2 | Add a required validator to the `ID` property
3 | Add a required validator to the `ID` property providing a custom validation error message
4 | Add an overall validator which reads the `ID` property value from the group `PropertyBox` and checks it is greater than 0

The input group validation is performed invoking all the available property validators, and then the overall group validators, if any.

    PropertyInputGroup group = createInputGroup();

    group.validate(); (1)

    PropertyBox value = group.getValue(); (2)

    value = group.getValue(false); (3)

    value = group.getValueIfValid().orElse(null); (4)

1 | Explicit group validation: if some kind of validation failure occurs, a `ValidationException` is thrown
2 | Using the default `getValue()` method, the validation is triggered automatically, and a `ValidationException` is thrown if validation fails
3 | The `getValue(boolean validate)` method can be used to skip value validation
4 | The `getValueIfValid()` returns an Optional, which contains the `PropertyBox` value only if the validation succeded

A ValidationStatusHandler can be used to control how the validation errors are notified to the user, listening to validation status change events.

The property input group supports `ValidationStatusHandler` configuration both for property and overall validation.

Furthermore, the input group builder provides two methods to control if the validation failures are to be collected and all notified to the user or if the validation has to stop at first failure, both from a properties or a group point of view.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyInputGroup group = Components.input.propertyGroup().properties(PROPERTIES) //
        .stopValidationAtFirstFailure(true) (1)
        .stopOverallValidationAtFirstFailure(true) (2)
        .validationStatusHandler(validationEvent -> { (3)
          // ...
        }).propertiesValidationStatusHandler(validationEvent -> { (4)
          // ...
        }).build();

1 | Set to stop overall validation at first failure
2 | Set to stop properties validation at first failure
3 | Set the overall `ValidationStatusHandler`
4 | Set the properties `ValidationStatusHandler`

| A property input group `ValidationStatusHandler` setter method which accept a `Label` is provided as a shorter to use a standard Vaadin `Label` to notify validation errors.

### 5.6. Input Forms

The PropertyInputForm represents an `Input` group bound to a `Property` model which is also a UI `Component`, and can be used to display and manage the `Input` components in the UI.

It is a Grouping Inputs, from which inherits all the `Input` generation, configuration and management features, using a `PropertyBox` to set and get the property values bound to each Input component.

It extends the ComposableComponent interface, which represents an UI component with a base layout and the capability to compose a set of UI components on this layout.

The `Composer` interface is used to compose the `Input` components on the UI, and must be provided to the `PropertyInputForm`, along with the base layout component on which the `Input` components will be organized.

| The `ComposableComponent` interface provides the `componentContainerComposer()` static method to obtain a default composer which uses a Vaadin `ComponentContainer` as base layout.

The inputs composition is triggered by using the `compose()` method. The `PropertyInputForm` builder provides a `composeOnAttach(…​)` method to set whether to automatically trigger the components composition when the form is attached to a parent layout, and this is the standard behaviour.

Furthermore, a `initializer(…​)` builder method is made available to perform custom configuration of the base layout component.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyInputForm form = Components.input.form(new FormLayout()).properties(PROPERTIES).required(ID).build(); (1)

    form = Components.input.form(new FormLayout()).properties(PROPERTIES).required(ID)
        .composer((layout, source) -> { (2)
          source.getValueComponents().forEach(c -> layout.addComponent(c.getComponent()));
        }).build();

    form.setValue(PropertyBox.builder(PROPERTIES).set(ID, 1L).set(DESCRIPTION, "Test").build()); (3)

    PropertyBox value = form.getValue(); (4)

1 | Create a `PropertyInputForm` with given property set using a FormLayout as base layout, and using the default composer
2 | Set a custom `Composer` to compose the Input components on the form layout
3 | Set the form value using a `PropertyBox`
4 | Get the form value

A set of default builder factory methods are provided to use the most common Vaadin layout components as form base content.

    PropertyInputForm form = Components.input.form().properties(PROPERTY_SET).build(); (1)
    form = Components.input.formVertical().properties(PROPERTY_SET).build(); (2)
    form = Components.input.formHorizontal().properties(PROPERTY_SET).build(); (3)
    form = Components.input.formGrid().properties(PROPERTY_SET)
        .initializer(gridLayout -> gridLayout.setSpacing(true)).build(); (4)

1 | Create a `PropertyInputForm` using a `FormLayout` as base content
2 | Create a `PropertyInputForm` using a `VerticalLayout` as base content
3 | Create a `PropertyInputForm` using a `HorizontalLayout` as base content
4 | Create a `PropertyInputForm` using a `GridLayout` as base content and setting an initializer function to perform GridLayout configuration

### 5.7. View components

The ViewComponent represents a UI component which can be used to display a value on the user interface. Unlike a `Input` component the value cannot be changed by the user.

As a `ValueHolder`, the view component value can be setted and obtained using the `setValue` and `getValue` methods.

The actual UI component to display is obtained form the `getComponent()` method.

A Vaadin `Label` is used for the default `ViewComponent` implementation, and a default view component can be built using the default builder which can be obtained from the `builder(Class valueType)` method or from the `Components.view` interface.

    ViewComponent<String> view = Components.view.component(String.class)
        .caption("TheCaption", "caption.message.code").icon(VaadinIcons.CAMERA).styleName("my-style").build(); (1)

    view.setValue("TestValue"); (2)
    String value = view.getValue(); (3)

1 | Create and configure a `ViewComponent` with a `String` value type
2 | Set the value
3 | Get the value

#### 5.7.1. View component Groups and Forms

Just like the `Input` components, the `ViewComponent` s can be organized in groups (using the PropertyViewGroup) or in forms (using the PropertyViewForm). Unlike the group, the form is a UI component which can be displayed in the user interface, composing the view components on a base layout.

These component containers rely on the `Property` model to bind each view component to a `Property` value and they use a `PropertyBox` to provide the property values to show.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyViewGroup viewGroup = Components.view.propertyGroup().properties(PROPERTIES).build(); (1)

    PropertyViewForm viewForm = Components.view.formVertical().properties(PROPERTIES).build(); (2)

    viewForm = Components.view.form(new FormLayout()).properties(PROPERTIES) //
        .composer((layout, source) -> { (3)
          source.getValueComponents().forEach(c -> layout.addComponent(c.getComponent()));
        }).build();

    viewForm.setValue(PropertyBox.builder(PROPERTIES).set(ID, 1L).set(DESCRIPTION, "Test").build()); (4)

    PropertyBox value = viewForm.getValue(); (5)

1 | Create a `PropertyViewGroup`
2 | Create a `PropertyViewForm` using a `VerticalLayout` as base layout
3 | Create a `PropertyViewForm` using a `FormLayout` as base layout and providing a custom components composer
4 | Set the form value using a `PropertyBox`
5 | Get the form value

## 6. Item listing

The ItemListing component can be used to display a set of items as tabular data. By default, it is backed by a Vaadin `Grid` as concrete UI component.

Each item property to display is bound to a column, and a Property id is used to bind the item property to the listing column.

The `ItemListing` is a Selectable component, supporting items selection in single or multiple mode.

The `ItemListing` interface provides a set of methods to control the listing appearance, showing and hiding columns, sorting and refreshing the item set, and so on.

Two `ItemListing` sub-interfaces are available to use this component:

- BeanListing: Uses a Java Bean as item type and the listing column ids are the bean property names.

- PropertyListing: Uses a `PropertyBox` as item type and the listing column ids are the `Property` of the provided property set.

### 6.1. BeanListing

A BeanListing can be obtained providing the Java Bean class to use as item type.

The listing columns will be generated inspecting the bean class to detect the available bean properties, and the column ids will be the bean property names.

    private class TestData {

      private Long id;
      private String description;

      // getters and setters omitted

    }

    public void beanListing() {
      BeanListing<TestData> listing = Components.listing.items(TestData.class) (1)
          .header("id", "The ID") (2)
          .header("description", "The description") (3)
          .build();

      listing.refresh(); (4)
    }

1 | Create a `BeanListing` using the `TestData` bean class
2 | Set the column header for the `id` item (bean) property
3 | Set the column header for the `description` item (bean) property
4 | Refresh the items set

### 6.2. PropertyListing

A PropertyListing can be obtained by providing the `Property` set to use for the listing items.

The listing columns will be generated according to the item property set `Property` types and each column will be identified by the `Property` itself.

For each property:

- The property caption, if available, will be used as column header. The caption/header localization is fully supported and performed if a `LocalizationContext` is available;

- The cells of the column which corresponds to a property will be rendered according to the property type and relying on the available property value presenters;

- For any property of `com.vaadin.ui.Component` type, a `ComponentRenderer` will be automatically used to render the Vaadin components in the cells.

    final PathProperty<Long> ID = PathProperty.create("id", Long.class);
    final PathProperty<String> DESCRIPTION = PathProperty.create("description", String.class);

    final PropertySet<?> PROPERTIES = PropertySet.of(ID, DESCRIPTION);

    PropertyListing listing = Components.listing.properties(PROPERTIES).build(); (1)

1 | Create a `PropertyListing` using given `Property` set

### 6.3. Items data source

To build an item listing, the data source of the items must be provided using the ItemDataProvider interface.

    ItemDataProvider<PropertyBox> dataProvider = getDataProvider();
    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .dataSource(dataProvider) (1)
        .build();

1 | Create a `PropertyListing` and provide an `ItemDataProvider` as data source

Furthermore, an ItemIdentifierProvider should be configured to provide the item identifiers, expecially for the item selection consistency. The default behaviour is to use the item itself as its own identifier, which it is not always the right semantic to use, expecially for `PropertyBox` type objects.

    ItemDataProvider<PropertyBox> dataProvider = getDataProvider();

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .dataSource(dataProvider, item -> item.getValue(ID)) (1)
        .build();

    listing = Components.listing.properties(PROPERTIES) //
        .dataSource(dataProvider, ID) (2)
        .build();

1 | Create a `PropertyListing` and provide an `ItemDataProvider` as data source, along with an `ItemIdentifierProvider` which provides the value of the `ID` property as item id
2 | A shorter builder method to use the `ID` property as item identifier

The item listing builders make available convenience methods to use a `Datastore` as data source, providing the `DataTarget` to use as target of the query on the backend data (for example, the name of a RDBMS table).

    Datastore datastore = getDatastore();

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .dataSource(datastore, DataTarget.named("test"), ID) (1)
        .build();

1 | Create a `PropertyListing` and use a `Datastore` to build a data source which performs a query using the `test` data target (which can be, for example, the name of a RDBMS table), the property set of the listing as query projection and the `ID` property as item identifier

### 6.4. Columns configuration

The listing component columns can be configured in a number of ways:

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .header(ID, "Custom ID header") (1)
        .columnHidingAllowed(true) (2)
        .hidable(ID, false) (3)
        .columnReorderingAllowed(true) (4)
        .alignment(ID, ColumnAlignment.RIGHT) (5)
        .hidden(DESCRIPTION, true) (6)
        .resizable(ID, false) (7)
        .width(ID, 100) (8)
        .expandRatio(DESCRIPTION, 1) (9)
        .minWidth(DESCRIPTION, 200) (10)
        .maxWidth(DESCRIPTION, 300) (11)
        .style(ID, (property, item) -> item.getValue(DESCRIPTION) != null ? "empty" : "not-empty") (12)
        .withPropertyReorderListener((properties, userOriginated) -> { (13)
          // ...
        }).withPropertyResizeListener((property, widthInPixel, userOriginated) -> { (14)
          // ...
        }).withPropertyVisibilityListener((property, hidden, userOriginated) -> { (15)
          // ...
        }).build();

1 | Set a custom header caption for the `ID` property/column
2 | Set whether the listing columns can be hidden
3 | Set that the `ID` property/column cannot be hidden
4 | Set whether the listing columns can reordered
5 | Set the `ID` property/column cell contents alignment
6 | Set the `DESCRIPTION` property/column as hidden by default
7 | Set the `ID` property/column as not resizable
8 | Set the `ID` property/column width in pixels
9 | Set the `DESCRIPTION` property/column expand ratio
10 | Set the `DESCRIPTION` property/column minimum width
11 | Set the `DESCRIPTION` property/column maximum width
12 | Set the `ID` property/column CSS style generator
13 | Add a listener to be notified when the listing columns order changes
14 | Add a listener to be notified when a property/column is resized
15 | Add a listener to be notified when a property/column is shown or hidden

### 6.5. Column rendering

The default column rendering can be overridden using a custom vaadin `Renderer`. The `Renderer` must handle the same data type of the property/column for which it is configured.

Furthermore, a property/column value can be converted to a different value type, and, in this case, a suitable `Renderer` for the converted type must be provided.

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .render(ID, new NumberRenderer(Locale.US)) (1)
        .render(ID, value -> String.valueOf(value), new TextRenderer()) (2)
        .build();

1 | Set a custom `NumberRenderer` for the `ID` property/column (which is of type `Long`)
2 | Set a converter to convert the `Long` type value of the `ID` property/column into a `String` and a suitable render according to the new value type

### 6.6. Listing configuration

The item listing component is highly configurable. Through the builders you can configure:

- The header appeareance, adding and removing header rows and joining header columns

- Showing and configuring a footer section

- Set a number of column as frozen

- Provide rows CSS style using a style generator

- Provide item description (tooltip) for item rows

- Provide a item click listener to listen for user clicks on item rows

- Provide a row details component which can be shown for each item row

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .heightByContents() (1)
        .frozenColumns(1) (2)
        .hideHeaders() (3)
        .withRowStyle(item -> { (4)
          return item.getValue(DESCRIPTION) != null ? "has-des" : "no-nes";
        }) //
        .itemDescriptionGenerator(item -> item.getValue(DESCRIPTION)) (5)
        .detailsGenerator(item -> { (6)
          VerticalLayout component = new VerticalLayout();
          // ...
          return component;
        }).withItemClickListener((item, property, event) -> { (7)
          // ...
        }).header(header -> { (8)
          header.getDefaultRow().setStyleName("my-header");
        }).footer(footer -> { (9)
          footer.appendRow().setStyleName("my-footer");
        }).footerGenerator((source, footer) -> { (10)
          footer.getRowAt(0).getCell(ID).setText("ID footer");
        }).withPostProcessor(grid -> { (11)
          // ...
        }).build();

1 | Set the height of the listing defined by its contents
2 | Set the frozen columns count
3 | Hide all the listing headers
4 | Set the row CSS style generator
5 | Set the item/row description (tooltip) generator
6 | Set the item/row details component generator
7 | Register a item click listener
8 | Add a style class name to the default header row
9 | Append a row to the listing footer and set a style class name for it
10 | Set the footer generator to invoke to update the listing footer contents
11 | Set a post-processor to customize the internal `Grid` component

### 6.7. Item selection

The item listing component supports items selection, both in single and multiple mode. The listing can be made selectable by using the `setSelectionMode` method or the `selectionMode` builder method.

Just like any other `Selectable` component, the item listing component provides methods to inspect the current selected item/s and change the current selection.

Single selection mode

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .selectionMode(SelectionMode.SINGLE) (1)
        .build();

    final PropertyBox ITEM = PropertyBox.builder(PROPERTIES).set(ID, 1L).build();

    PropertyBox selected = listing.getFirstSelectedItem().orElse(null); (2)

    boolean isSelected = listing.isSelected(ITEM); (3)

    listing.select(ITEM); (4)

    listing.deselectAll(); (5)

1 | Set the listing selectable in `SINGLE` selection mode
2 | Get the currently selected item, if any
3 | Check whether the given item is selected
4 | Select the given item
5 | Deselect all (clear current selection)

Multiple selection mode

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .build();

    listing.setSelectionMode(SelectionMode.MULTI); (1)

    final PropertyBox ITEM = PropertyBox.builder(PROPERTIES).set(ID, 1L).build();

    Set<PropertyBox> selected = listing.getSelectedItems(); (2)

    boolean isSelected = listing.isSelected(ITEM); (3)

    listing.select(ITEM); (4)

    listing.deselectAll(); (5)

    listing.selectAll(); (6)

1 | Set the listing selectable in `MULTI` selection mode
2 | Get the selected items
3 | Check whether the given item is selected
4 | Select the given item
5 | Deselect all items
6 | Select all items

| The select all checkbox shown in the top left corner of the listing is visible by default. You can control the checkbox visibility using the `selectAllCheckBoxVisibility(…​)` method of the item listing builder.

### 6.8. Item query configuration

The item listing builder provides a number of methods to control the data source items query, allowing to:

- Set a property/column as sortable or not and override the default sort behaviour, for example using another property as query sort target or providing a custom `QuerySort`;

- Set a fixed sort, which will be always appended to current query sorts

- Set a default sort, to be used when no other query sort is configured

- Set a fixed filter, which will be always applied to the query

- Register one or more `QueryConfigurationProvider` to provide custom query configuration logic

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .sortable(ID, true) (1)
        .sortUsing(ID, DESCRIPTION) (2)
        .sortGenerator(ID, (property, ascending) -> { (3)
          return ascending ? ID.asc() : ID.desc();
        }) //
        .fixedSort(ID.asc()) (4)
        .defaultSort(DESCRIPTION.asc()) (5)
        .fixedFilter(ID.gt(0L)) (6)
        .withQueryConfigurationProvider(() -> DESCRIPTION.isNotNull()) (7)
        .build();

1 | Set the `ID` property/column as sortable
2 | Set to use the `DESCRIPTION` property to sort the `ID` property/column
3 | Set a custom `QuerySort` for the `ID` property/column
4 | Set a fixed `QuerySort`, which will always to appended to current query sorts
5 | Set the default `QuerySort`, to be used when no other query sort is configured
6 | Set a fixed `QueryFilter`
7 | Add a `QueryConfigurationProvider`

### 6.9. Item set management

The item set component provides methods to manage the item set which is provided as the listing data source, to add, update and remove one or more items in the set.

To reflect the item set management operations in the underlyng data source (for example, a RDBMS), the `CommitHandler` interface is used. The `commit(…​)` method of that interface is invoked at each item set modification, providing the added, updated and removed items. The `CommitHandler` implementation should persist the item set modifications in the concrete data source.

| When using the `dataSource(…​)` builder method which accepts a `Datastore` as data source, a default `CommitHandler` is automatically configured, using the provided `Datastore` to perform the item persistence operations.

    Datastore datastore = getDatastore();

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .dataSource(datastore, DataTarget.named("test"), ID) (1)
        .commitHandler((addedItems, modifiedItems, removedItems) -> { (2)
          // ...
        }).build();

    final PropertyBox ITEM = PropertyBox.builder(PROPERTIES).set(ID, 777L).set(DESCRIPTION, "A description")
        .build();

    listing.addItem(ITEM); (3)

    listing.refreshItem(ITEM); (4)

    listing.removeItem(ITEM); (5)

1 | When using the `Datastore` method of the data source builder, a default `CommitHandler` is automatically configured
2 | You can provide a custom `CommitHandler` using the `commitHandler(…​)` builder method
3 | Add an item
4 | Refresh (update) the item
5 | Remove the item

#### 6.9.1. Buffered mode

The item set component supports a buffered mode to handle its items set. When in buffered mode, the item set modifications are cached internally and not reflected to the concrete data source until the `commit()` method is called.

A `discard()` method is provided to discards all changes since last commit.

The same `CommitHandler` as before is used to persist the item set modifications, but it is invoked only when the `commit()` method is called.

    Datastore datastore = getDatastore();

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .dataSource(datastore, DataTarget.named("test"), ID) //
        .buffered(true) (1)
        .build();

    final PropertyBox ITEM = PropertyBox.builder(PROPERTIES).set(ID, 777L).set(DESCRIPTION, "A description")
        .build();

    listing.addItem(ITEM); (2)
    listing.refreshItem(ITEM); (3)
    listing.removeItem(ITEM); (4)

    listing.commit(); (5)
    listing.discard(); (6)

1 | Set the listing in buffered mode
2 | Add an item
3 | Refresh (update) the item
4 | Remove the item
5 | commit the item set modifications
6 | discard the item set modifications since the last commit

### 6.10. Editing items

The item listing component supports line-based editing, where double-clicking a row opens the row editor, using the default Vaadin `Grid` editor. The item listing editor must be enabled using the `editable(true)` method of the builder in order to activate the row editor at double-click.

The editor fields to use for each listing property/column will be auto-generated according to the property/column type. This behaviour can be overridden providing custom editor fields for one or more of the listing properties.

The item listing component editor supports validation, allowing to register value validators both for the single property/column fields and for the overall value validation.

    PropertyListing listing = Components.listing.properties(PROPERTIES) //
        .editable(true) (1)
        .editorBuffered(true) (2)
        .editorSaveCaption("Save item") (3)
        .editorCancelCaption("Discard") (4)
        .editable(ID, false) (5)
        .editor(DESCRIPTION, new TextField()) (6)
        .withValidator(Validator.create(pb -> pb.getValue(DESCRIPTION) != null, "Description must be not null")) (7)
        .withValidator(DESCRIPTION, Validator.max(100)) (8)
        .required(ID) (9)
        .build();

1 | Set the listing as editable
2 | Set the row editor in buffered mode
3 | Set the editor save button caption
4 | Set the editor cancel button caption
5 | Set a property as not editable
6 | Set a custom editor field
7 | Add an overall value validator
8 | Add a property value validator
9 | Set the `ID` property as required, automatically adding a not empty validator

## 7. Dialogs

The Holon Vaadin module provides builders to create and show dialog windows.

A dialog window in represented by the Dialog interface, which makes available methods to set the dialog as modal, open and close the dialog window and registere a `CloseListener` to be invoked when the dialog is closed.

    Dialog dialog = Components.dialog() (1)
        .draggable(false) (2)
        .closable(true) (3)
        .resizable(true) (4)
        .modal(true) (5)
        .message("Dialog message", "dialog.message.code") (6)
        .okButtonConfigurator(cfg -> cfg.caption("Done").icon(VaadinIcons.CHECK_CIRCLE_O)) (7)
        .withCloseListener((window, action) -> { (8)
          // ...
        }).build();

    dialog.open(); (9)

    dialog.close(); (10)

1 | Dialog builder
2 | Set as not draggable
3 | Set as closable
4 | Set as resizable
5 | Set as modal
6 | Set the localizable dialog message
7 | Configure the dialog OK button
8 | Add a close listener
9 | Open (show) the dialog
10 | Close (hide) the dialog

### 7.1. Question dialogs

A question dialog is a `Dialog` with a message and two buttons (instead of one) to answer yes or no to a question.

A `QuestionCallback` can be used when the user selects one of the two buttons and the dialog is closed. The callback notifies the selected answer.

    Components.questionDialog() (1)
        .message("Can I do it for you?") (2)
        .yesButtonConfigurator(cfg -> cfg.caption("Ok, let's do it")) (3)
        .noButtonConfigurator(cfg -> cfg.caption("No, thanks")) (4)
        .callback(answeredYes -> { (5)
          Notification.show("Ok selected: " + answeredYes);
        }).build().open(); (6)

1 | Question dialog builder
2 | Set the dialog message (the question)
3 | Change the yes button caption
4 | Change the no button caption
5 | Set the answer callback
6 | Build and open the dialog

## 8. Property renderers and presenters

The Vaadin module takes advantage of the platform foundation property model to provide the most suitable UI components and display values when a `Property` is used.

When a `Property` must be rendered in UI, the components made available by the Vaadin module try to use a suitable `PropertyRenderer`, if available.

By default, the following renderers are automatically registered by the module:

- A Input property renderer

- A Field property renderer, which represents a `HasValue` Vaadin `Component`

- A ViewComponent property renderer

The `Input` and `Field` property renderers generate a UI component to edit a property value, relying on the property type.

The following types are supported:

- String: renders the property as a `TextField`

- Boolean: renders the property as a `CheckBox`

- Enum: renders the property as a `ComboBox`

- LocalDate and LocalDateTime: renders the property as a `DateField` or a `DateTimeField`

- java.util.Date: renders the property as a `DateField` or a `DateTimeField`

- Number: renders the property as a `TextField` which only accepts numbers and decimal/group separators

    final PathProperty<String> TEXT = PathProperty.create("text", String.class);
    final PathProperty<Long> LONG = PathProperty.create("long", Long.class);

    Input<String> input = TEXT.render(Input.class); (1)

    Field<Long> field = LONG.render(Field.class); (2)

    ViewComponent<String> view = TEXT.render(ViewComponent.class); (3)

1 | Render the property as `String` type `Input`
2 | Render the property as `Long` type `Field` (`HasValue` component)
3 | Render the property as `String` type `ViewComponent`

### 8.1. Property localization

When a `LocalizationContext` is available as a Context resource, it is used to localize any element to display which supports localization. Concerning to a `Property` related UI component, it is used to:

- Localize the property caption, for example when it is used as a listing column header or as a input field caption

- Obtain the date and time format to use to display a property value or to edit the property value through an input field

- Obtain the number format to be used to display a property value or to edit the property value through an input field

- Obtain the default boolean localized text for the `true` and `false` values

| See the Internationalization documentation for further information about localization.

### 8.2. Custom property renderers

Relying on the standard property renderers features, custom renderers can be registered to:

- Customize the rendered UI component under certain conditions for the default provided rendering types (`Input`, `Field` and `ViewComponent`)

- Provide the rendering for a custom type

For example, to render a specific `String` type property as text area, instead of the default text field, an appropriate renderer can be registered and bound to a suitable property condition:

    final PathProperty<String> TEXT = PathProperty.create("text", String.class);

    InputPropertyRenderer<String> textAreaInputRenderer = p -> Components.input.string(true).build(); (1)

    PropertyRendererRegistry.get().register(p -> p == TEXT, textAreaInputRenderer); (2)

    Input<String> input = TEXT.render(Input.class); (3)

1 | Create a `Input` property renderer which renders the property as a text area
2 | Register the renderer and bind it to a condition which checks the property is exactly the `TEXT` property
3 | From now on, rendering the `TEXT` property as an `Input` field will generate a text area input component

## 9. Vaadin session scope

A Vaadin session platform scope is automatically registered by the Holon Vaadin module.

This `ContextScope` is bound to the current `VaadinSession`, looking up context resources using Vaadin Session attributes.

The scope uses `VaadinSession.getCurrent()` to obtain the current Vaadin session, so this scope is active only when invoked within a Vaadin server request thread.

| See the Context documentation for further information about context scopes and resources.

    VaadinSession.getCurrent().setAttribute(LocalizationContext.CONTEXT_KEY,
        LocalizationContext.builder().withInitialLocale(Locale.US).build()); (1)

    LocalizationContext.getCurrent().ifPresent(localizationContext -> { (2)
      // LocalizationContext obtained from current Vaadin session
    });

1 | Create a `LocalizationContext` and set it in Vaadin session using the default context key as attribute name
2 | Get the current `LocalizationContext` context resource, which will be obtained form the Vaadin session, if available

## 10. Device information

The Holon platform Vaadin module makes available the DeviceInfo interface, to obtain informations about the device in which the application is running.

The `DeviceInfo` object provides informations about the user agent and screen dimensions, and can be obtained by using a `VaadinRequest` or relying on the currently available `VaadinSession`.

    DeviceInfo.get().ifPresent(info -> {

      info.getScreenWidth();
      info.getScreenHeight();
      info.getViewPortWidth();
      info.getViewPortHeight();
      info.isMobile();
      info.isTablet();
      info.isSmartphone();
      info.isAndroid();
      info.isIPhone();
      // ...

    });

## 11. Navigator

The `holon-vaadin-navigator` artifact makes available an extension of the default view navigator, represented by the ViewNavigator interface, which provides additional features and configuration capabilities:

- `View` navigation history tracking, allowing to navigate back to the previous view

- `View` parameters management, allowing to obtain the parameters values by injection in the `View` instance

- Easy `View` lifecycle management, supporting `OnShow` and `OnLeave` annotated methods to be notified when the view is loaded and unloaded in the UI

- Default view support, acting as the application’s "home page"

- The possibility to show a view in a `Window`, instead of using the default view display component

- Support for context resources injection in `View` instances

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-vaadin-navigator</artifactId>
    <version>5.0.1</version>

### 11.1. View configuration

#### 11.1.1. Parameters injection

The navigation parameters can be injected in the `View` class fields using the ViewParameter annotation.

The parameter name for which the value has to be injected in an annotated field is assumed to be equal to the field name. Otherwise, it can be specified using the annotation `value()` property.

When a named parameter value is not available (not provided by the current navigation state), the parameter field will be setted to `null` or the default value for primitive types (for example `0` for `int`, `long`, `float` and `double` types, false for `boolean` types).

The supported parameter value types are:

- `String`

- `Number` s (including primitive types)

- `Boolean` (including primitive type)

- `Enum`

- `Date`

- `LocalDate`

- `LocalTime`

- `LocalDateTime`

A view parameter can be declared as required using the `required()` annotation property. A navigation error will be thrown if a required parameter value is missing.

Furthermore, a default value can be provided for a parameter, using the `defaultValue()` annotation property. See the ViewParameter javadocs for information about the default value representation.

    class ViewExample implements View {

      @ViewParameter("myparam") (1)
      private String stringParam;

      @ViewParameter(defaultValue = "1") (2)
      private Integer intParam;

      @ViewParameter(required = true) (3)
      private LocalDate requiredParam;

    }

1 | View parameter injection using the `myparam` parameter name
2 | View parameter with a default value. The parameter name will be the `intParam` field name
3 | A required view parameter declaration

#### 11.1.2. View lifecycle hooks

In addition to the standard `enter(…​)` method of the `View` interface, two annotations can be used to intercept `View` lifecycle events using `public` View methods:

- OnShow, called by the view navigator right before the view is shown (i.e. rendered in target display component)

- OnLeave, called by the view navigator when the view is about to be deactivated (i.e. a navigation to another view was triggered)

If more than one `OnShow` or `OnLeave` annotated method is present in the `View` class or in its class hierarchy, all these methods will be called and the following behaviour will be adopted:

- Methods will be called following the class hierarchy, starting from the top (the first superclass after `Object`)

- For methods of the same class, no calling order is guaranteed

The `OnShow` and `OnLeave` annotated method supports an optional parameter, which can be either of the standard `com.vaadin.navigator.ViewChangeEvent` type or of the extended `ViewNavigatorChangeEvent` type, to obtain informations about the current view navigator, the previous or next `View`, the `View` name and parameters and the optional `Window` in which the View is displayed.

The `OnShow` annotation provides an additional `onRefresh()` property which, if setted to `true`, instruct the navigator to invoke the `OnShow` annotated method also at browser page refresh.

    class ViewExample2 implements View {

      @ViewParameter
      private String myparam;

      @OnShow
      public void onShow() { (1)
        // ...
      }

      @OnShow(onRefresh = true) (2)
      public void onShowAtRefreshToo() {
        // ...
      }

      @OnShow
      public void onShow2(ViewChangeEvent event) { (3)
        String name = event.getViewName(); (4)
        View oldView = event.getOldView(); (5)
        // ...
      }

      @OnShow
      public void onShow3(ViewNavigatorChangeEvent event) { (6)
        ViewNavigator navigator = event.getViewNavigator(); (7)
        Optional<Window> viewWindow = event.getWindow(); (8)
        // ...
      }

      @OnLeave
      public void onLeave() { (9)
        // ...
      }

      @OnLeave
      public void onLeave2(ViewNavigatorChangeEvent event) { (10)
        View nextView = event.getNewView(); (11)
        // ...
      }

    }

1 | Basic `OnShow` annotated method, invoked right before the view is shown
2 | `OnShow` method with `onRefresh()` setted to `true`: this method will be invoked also at browser page refresh
3 | `OnShow` method with a default `ViewChangeEvent` parameter
4 | Get the View name
5 | Get the previous View
6 | `OnShow` method with a `ViewNavigatorChangeEvent` parameter
7 | Get the `ViewNavigator`
8 | Get the `Window` in which the view is displayed if it was requested to open the View in a window
9 | Basic `onLeave` annotated method
10 | `onLeave` method with a `ViewNavigatorChangeEvent` parameter
11 | Get the View being activated

#### 11.1.3. Providing the View contents

By default, the `View` is rendered as the UI component which is represented by the `View` class.

You can override the standard Vaadin 8 `getViewComponent()` method of the `View` class to control which `Component` to provide as `View` content.

    class ViewExampleContent extends VerticalLayout implements View { (1)

      public ViewExampleContent() {
        super();
        addComponent(new Label("View content"));
      }

    }

    class ViewExampleContentProvider implements View {

      @Override
      public Component getViewComponent() { (2)
        boolean mobile = DeviceInfo.get().map(info -> info.isMobile()).orElse(false);
        return mobile ? buildMobileViewContent() : buildDefaultViewContent();
      }

    }

1 | Default `View` implementation extending a `Component` class (a `VerticalLayout`). The displayed `View` content will be the component itself
2 | Provide the `View` content using the `getViewComponent()` method. In this example, a different UI component is provided according to the device type, checking if the user is running the application in a mobile device

### 11.2. Navigator Configuration

Just like the standard Vaadin navigator, the `ViewNavigator` requires two elements which must be configured in order to work properly:

- A `ViewProvider` to provide the `View` instances by view name

- A `View` display component to show the view contents in the UI, which can be a `ComponentContainer` (replacing the contents of the container with the active `View` content), a `SingleComponentContainer` (using the `setContent(…​)` method to set the active `View` content) or a `ViewDisplay` object to implement a custom `View` display logic.

In addition to the required configuration elements, the `ViewNavigator` supports:

- Setting a default view name, which will be used as target of the `ViewNavigator.navigateToDefault()` method and as a fallback by the `ViewNavigator.navigateBack()` method if no other `View` is available in navigation history

- Setting a error view or a error `ViewProvider` to provide the `View` to be displayed when no other `View` matches a navigation state

- Setting the max navigation history size

- Register a `ViewChangeListener` for listening to `View` changes before and after they occur

The `builder()` method of the `ViewNavigator` interface provides a fluent builder to configure a navigator and bind it to a Vaadin `UI`.

    class AppUI extends UI {

      @Override
      protected void init(VaadinRequest request) {
        ViewNavigator navigator = ViewNavigator.builder() (1)
            .viewDisplay(this) (2)
            .addProvider(getViewProvider()) (3)
            .defaultViewName("home") (4)
            .errorView(MY_ERROR_VIEW) (5)
            .errorViewProvider(getErrorViewProvider()) (6)
            .maxNavigationHistorySize(1000) (7)
            .navigateToDefaultViewWhenViewNotAvailable(true) (8)
            .withViewChangeListener(e -> { (9)
              // ...
              return true;
            }).buildAndBind(this); (10)
      }

    }

1 | Obtain the `ViewNavigator` builder
2 | Set the component to which the `View` contents display is delegated
3 | Add a `ViewProvider`
4 | Set the default `View` name
5 | Set the error `View`
6 | Set the error `View` provider
7 | Set the max navigation history size
8 | Configure the navigator to navigate to default `View` (if availablr) when a view is not available according to current navigation state
9 | Add a `ViewChangeListener`
10 | Build the `ViewNavigator` and bind it to the `UI`

The `ViewNavigator` builder makes available a default `View` provider, which supports a fixed set of `Views` configured using a View name bound to a View class.

Stateful views are supported by this provider. To declare a View as stateful, the StatefulView annotation can be used on the View class.

View instances will be created according to view scope: for stateful views, an instance is created at first request (for each UI) and the same instance is returned to subsequent view requests. On the contrary, for standard views, a new instance is created and returned to navigator for every view request.

To register this view provider and configure the `View` set, the `ViewNavigator` builder method `withView(String viewName, Class<? extends View> viewClass)` can be used.

    UI ui = getUI();
    ViewNavigator.builder() //
        .viewDisplay(ui) //
        .withView("view1", View1.class) (1)
        .withView("view2", View2.class) (2)
        .defaultViewName("view1") (3)
        .buildAndBind(ui);

1 | Register the view class `View1` and bind it the `view1` name
2 | Register the view class `View2` and bind it the `view2` name
3 | Set the `view1` View as the default view

### 11.3. Excluding a View form navigation history

By default, the `ViewNavigator` tracks views navigation history, to made available navigation operations such `navigateBack()` to navigate to the previous view.

To exclude a `View` from the navigation history, skipping such View when a `navigateBack()` operation is performed or the user presses the browser back button, the VolatileView annotation can be used on the `View` class.

    @VolatileView
    class VolatileViewExample implements View {

    }

### 11.4. Opening Views in a `Window`

The `ViewNavigator` supports displaying a `View` content in a application `Window`. The view navigation is tracked in navigator history just like any other navigation operation.

To open a `View` in a `Window`, the `navigateInWindow(…​)` view navigator methods can be used (see the next section), or a `View` class can be forced to be always opened in a window using the WindowView annotation.

If the `@WindowView` annotation is found on a view class, such view will be always opened in a window, regardless of the navigation operation that is used.

The `Window` is automatically created by the `ViewNavigator`, and can be configured using either a `ViewWindowConfigurator`, when the navigator method is used, or the `@WindowView` annotation attributes.

    @WindowView(windowWidth = "50%")
    class WindowViewExample implements View {

    }

### 11.5. View navigation operations

The `ViewNavigator` API provides navigation methods to provide a set of parameters to the `View` being activated.

These parameters are serialized in the navigation state String, and are automatically bound to the any `View` class field annotated with the `@ViewParameter` annotation.

See Parameters injection for further informations about `View` parameters injection.

| When using `@ViewParameter` annotated `View` methods, the parameter value types provided to a view navigation method through the name-value Map must be consistent with the corresponding `@ViewParameter` view class field type.

The `ViewNavigator` API provides the following operations for `View` navigation:

- `navigateTo(String viewName, Map<String, Object> parameters)`: navigate to given `View` name, providing an optional Map of parameters with parameters names and corresponding values.

- `navigateTo(String viewName)`: navigate to given `View` name without providing any view parameter.

    ViewNavigator navigator = getViewNavigator();

    navigator.navigateTo("myView"); (1)

    Map<String, Object> parameters = new HashMap<>();
    parameters.put("parameter1", "test");
    parameters.put("parameter2", 34.5);

    navigator.navigateTo("myView", parameters); (2)

1 | Navigate to the view named `myView`
2 | Navigate to the view named `myView` providing a map of parameters (names and values)

    ViewNavigator navigator = getViewNavigator();

    navigator.navigateInWindow("myView"); (1)

    Map<String, Object> parameters = new HashMap<>();
    parameters.put("parameter1", "test");
    parameters.put("parameter2", 34.5);

    navigator.navigateInWindow("myView", windowConfig -> {
      windowConfig.fullWidth();
      windowConfig.styleName("my-window-style");
    }, parameters); (2)

1 | Navigate to the view named `myView` and display the view in a Window
2 | Navigate to the view named `myView` and display the view in a Window, providing a window configuration consumer and a map of parameters

    ViewNavigator navigator = getViewNavigator();

    navigator.toView("myView").withParameter("parameter1", "test").withParameter("parameter2", 34.5).navigate(); (1)

    navigator.toView("myView").navigateInWindow(); (2)

    navigator.toView("myView").navigateInWindow(windowConfig -> {
      windowConfig.fullWidth();
      windowConfig.styleName("my-window-style");
    }); (3)

1 | Navigate to the view named `myView` using given parameters
2 | Navigate to the view named `myView` and display the view in a Window
3 | Navigate to the view named `myView` and display the view in a Window, providing a window configuration consumer

### 11.6. Sub views

The `ViewNavigator` supports the concept of sub view: a sub view is a `View` which is always displayed using a parent view container, and the sub view display strategy is delegated to the container.

A sub view container is a conventional `View` which implements the SubViewOf interface.

Any sub view must declare its parent container view name using the WindowView annotation.

When the navigation to a sub view is triggered, the `ViewNavigator` first of all will navigate to the declared sub view container, displaying it as a normal `View`, then the `display(View view, String viewName, Map<String, String> parameters)` method of the sub view container is invoked providing the sub view instance, the sub view name and any navigation parameter. At this point, the container should display the sub view contents in a suitable way.

| The `getViewContent(View view)` static method of the `ViewNavigator` interface can be used to obtain the view contents from a `View` instance.

    class SubViewContainerExample extends TabSheet implements SubViewContainer { (1)

      public SubViewContainerExample() {
        super();
        setSizeFull();
      }

      @Override
      public boolean display(View view, String viewName, Map<String, String> parameters)
          throws ViewNavigationException {
        addTab(view.getViewComponent(), viewName, VaadinIcons.PIN);
        return true;
      }

      @Override
      public View getCurrentView() {
        return (View) getSelectedTab();
      }

    }

    @SubViewOf("mycontainer")
    public class SubViewExample extends VerticalLayout implements View { (2)

      public SubViewExample() {
        super();
        setMargin(true);
        addComponent(new Label("The sub view 1"));
      }

    }

1 | A view declared as `SubViewContainer` using a `TabSheet` to display each sub view in a new tab. We suppose this view is bound to the `mycontainer` view name
2 | A sub view bound to the `mycontainer` sub view container using the `@SubViewOf` annotation

### 11.7. Context resources injection

The `ViewNavigator` supports Context resources injection into the `View` instances. A resource available form the Holon platform `Context` registry can be injected in a `View` using the ViewContext annotation on a `View` field.

The resource to be injected is looked up by key, and by the default the resource key is assumed to be the fully qualified class name of the injectable field type. To override this strategy, the `value()` annotation attribute of the `ViewContext` annotation can be used to provide the resource key to look up.

| See the Context documentation for further information about context resources.

    class ViewContextExample implements View {

      @ViewContext
      private LocalizationContext localizationContext;

      @ViewContext
      private AuthContext authContext;

    }

### 11.8. Obtain the ViewNavigator

The `ViewNavigator` interface provides methods to obtain the current navigator using the following strategy:

- If the `ViewNavigator` is available as Context resource using the default navigator resource key, that instance is returned;

- If a current Vaadin `UI` is available and a `ViewNavigator` is bound to the `UI`, that instance is returned.

| See the Context documentation for further information about context resources.

    Optional<ViewNavigator> navigator = ViewNavigator.getCurrent(); (1)

    ViewNavigator viewNavigator = ViewNavigator.require(); (2)

1 | Try to obtain the `ViewNavigator` from context or current `UI`
2 | Obtain the `ViewNavigator` from context or current `UI`, failing with an exception if not found

### 11.9. Authentication support

The `ViewNavigator` architecture provides support for `View` authentication, relying on the default Holon platform `AuthContext` API.

| See the Realm and AuthContext documentation for information about the Holon platform authentication and authorization architecture.

In order for the authentication to work, an `AuthContext` instance must be available as a context resource, and it will be used to perform user authentication and resource access control, relying on the `Realm` bound to the auth context.

The authentication support is enabled by default, but it can be configured using the `authenticationEnabled(…​)` `ViewNavigator` builder method.

The authentication support is enabled through the standard `com.holonplatform.auth.annotations.Authenticate` annotation, which can be used on a `View` class or on the application `UI` class.

When the `Authenticate` annotation is used at `UI` level, all the views managed by the navigator bound to such `UI` will be under authentication, and the access to any `View` will be denied if an authenticated subject is not available from the current `AuthContext`.

Each time the navigation to a protected `View` is requested, the `AuthContext` is checked, and if it not authenticated, the following strategy is implemented:

1. An implicit authentication attempt is performed, using the current `VaadinRequest` and the optional authentication schemes which can be specified using the `schemes()` attribute of the `Authenticate` annotation. This behaviour can be used, for example, to support authentication using the current HTTP request and schemes such the `Authorization` HTTP header.

2. If the implicit authentication is not successfull and a valid redirect URI is provided through the `redirectURI()` property of the `Authenticate` annotation, the navigation is redirected to that URI. If the redirect URI does not specify a scheme, or the scheme is equal to the special `view://` scheme, the navigation is redirected to the navigation state specified by the redirect URI (escluding the `view://` part, if present). This way, the redirect URI can be used to delegate to a `View` an explicit authentication entry point (for example using conventional username and password credentials).

## 12. Spring integration

The `holon-vaadin-spring` artifact provides support and integration with the Spring framework.

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-vaadin-spring</artifactId>
    <version>5.0.1</version>

This artifact provides a `ViewNavigator` extension with Spring support, represented by the SpringViewNavigator interface.

The `SpringViewNavigator` implementation relies upon the standard Vaadin Spring integration add-on, and supports all its functionalities and configuration features.

See the Vaadin Spring tutorial for the documentation.

The following annotations are available for `View` configuration:

- DefaultView: can be used on a `View` class to declare it as the default view, i.e the view which will be used as target of the `ViewNavigator.navigateToDefault()` method and as a fallback by the `ViewNavigator.navigateBack()` method if no other `View` is available in navigation history.

- ErrorView: can be used on a `View` class to declare it as the default error view, i.e. the `View` to be displayed when no other `View` matches a navigation state.

### 12.1. Default View navigation strategy

When a statically declared default `View` (using for example the `@DefaultView` annotation) is not suitable for an application, the DefaultViewNavigationStrategy interface can be used to implement a custom strategy to provide the default navigation state.

When a `DefaultViewNavigationStrategy` type Spring bean is found in application context, it is automatically configured in View navigator as default view navigation stategy implementation.

### 12.2. Spring view navigator configuration

The `SpringViewNavigator` API provides a builder to create a navigator instance, and can be used to explicitly build and configure a `SpringViewNavigator` instance. The bulder can be obtained through the static `builder()` method of the `SpringViewNavigator` interface.

The easiest way to setup a Spring view navigator, is to use the provided EnableViewNavigator configuration annotation.

The `@EnableViewNavigator` can be used on Spring configuration classes to automatically setup the default Vaadin Spring integration and register a UI-scoped `SpringViewNavigator` bean. The standard `@SpringViewDisplay` annotation can be used to configure the views display component and the default Vaadin Spring `ViewProvider` will be used.

| The `@EnableViewNavigator` annotation includes the standard `com.vaadin.spring.annotation.@EnableVaadin` annotation behaviour, which is not required anymore on configuration classes.

The `@EnableViewNavigator` annotation makes available a number of properties to control the navigator configuration, for example to explicitly configure the default and error views or to set the max navigation history size. See the EnableViewNavigator javadocs for further information.

    @Configuration (1)
    @ComponentScan(basePackageClasses = ViewOne.class) (2)
    @EnableViewNavigator (3)
    @EnableBeanContext (4)
    class SpringConfig {

    }

    @SpringView(name = "view1") (5)
    @DefaultView (6)
    class ViewOne extends VerticalLayout implements View {

    }

    @SpringView(name = "view2") (7)
    @UIScope (8)
    class ViewTwo extends VerticalLayout implements View {

    }

    @SpringUI (9)
    @SpringViewDisplay (10)
    class AppUI extends UI {

      @Autowired
      ViewNavigator navigator; (11)

      @Override
      protected void init(VaadinRequest request) {
        // ...
      }

    }

1 | Declare the class as a Spring configuration class
2 | Set the component scan rule to auto detect the `View` beans
3 | Enable the Spring `ViewNavigator`
4 | Enable the Holon platform Spring context scope, to provide context resource instances as Spring beans
5 | Declare the view as Spring view (which will be automatically registered in the navigator view provider), and bind it to the `view1` name
6 | Declare the view as the default view
7 | Create another view and enable it as a Spring view using the `view2` name
8 | Declare the view bean scope as `UI`
9 | Create the application `UI` and declare it as a Spring `UI`, which will be automatically detected and configured by Spring
10 | Use the `UI` as `View` display container
11 | The `ViewNavigator` will be made avaialable as Spring (UI-scoped) bean, so it can be obtained using dependency injection

### 12.3. View context resources

The EnableViewContext annotation can be used on Spring configuration classes to enable `View` context resource injection using the ViewContext annotation.

See Context resources injection for further information.

### 12.4. View authorization support

In addition to the `ViewNavigator` authentication support (see Authentication support), the Spring view navigator provides View authorization support using default `javax.annotation.security.*` annotations (`@RolesAllowed`, `@PermitAll`, `@DenyAll`).

The authorization support can be enabled using the EnableViewAuthorization annotation and, just like the authentication support, relies on the current `AuthContext` to perform authorization control, so it must be available as a context resource.

| By using the `@EnableBeanContext` configuration annotation, Spring beans can be automatically configured as context resources. See the SpringContextScope documentation for further information.

| The default Vaadin Spring `ViewAccessControl` and `ViewInstanceAccessControl` view access control methods are fully supported too, and can be used along with the security annotations.

The AccessDeniedView annotation can be used on a Spring `View` class to declare it as the view to show when the user is not authorized to access a view, either according to a `javax.annotation.security.*` annotation or to a `ViewAccessControl` or `ViewInstanceAccessControl` rule.

    @Configuration
    @ComponentScan(basePackageClasses = ViewOne.class)
    @EnableViewNavigator
    @EnableBeanContext (1)
    @EnableViewAuthorization (2)
    class SpringConfig {

      @Bean (3)
      @VaadinSessionScope
      public AuthContext authContext() {
        AccountProvider ap = id -> {
          // Only a user with username 'username1' is available
          if ("username1".equals(id)) {
            // setup the user password and assign the role 'role1'
            return Optional.of(Account.builder(id).credentials(Credentials.builder().secret("s3cr3t").build())
                .permission("role1").build());
          }
          return Optional.empty();
        };
        return AuthContext.create(Realm.builder()
            // authenticator using the AccountProvider
            .authenticator(Account.authenticator(ap))
            // default authorizer
            .withDefaultAuthorizer().build());
      }

    }

    @SpringView(name = "view1")
    @PermitAll (4)
    class ViewOne extends VerticalLayout implements View {

    }

    @SpringView(name = "view2")
    @RolesAllowed("role1") (5)
    class ViewTwo extends VerticalLayout implements View {

    }

    @AccessDeniedView (6)
    @UIScope
    @SpringView(name = "forbidden")
    class AccessDenied extends VerticalLayout implements View {

      private static final long serialVersionUID = 1L;

      private final Label message;

      public AccessDenied() {
        super();
        Components.configure(this).margin()
            .add(message = Components.label().styleName(ValoTheme.LABEL_FAILURE).build());
      }

      @Override
      public void enter(ViewChangeEvent event) {
        message.setValue("Access denied [" + event.getViewName() + "]");
      }

    }

1 | Use `@EnableBeanContext` to enable Spring beans as context resources (in this example, the `AuthContext` bean will be available as context resource)
2 | Enable views authorization using `javax.annotation.security.*` annotations
3 | Configure the `AuthContext` and declare it as a session-scoped Spring bean
4 | Use `@PermitAll` on this view to skip authorization control
5 | Use `@RolesAllowed` to declare that the view is available only for the authenticated subjects with the `role1` role
6 | Create a custom access denied view using the `@AccessDeniedView` annotation

### 12.5. Spring Security support

The `View` access control using the Spring Security `@Secured` annotation can be enabled using the EnableSecuredView annotation.

This access control strategy relies on the Spring Security `SecurityContext` to check current authentication and performs View access control checking current user granted authorities against the security attributes specified through the `@Secured` annotation.

| The Spring Security artifacts must be explicitly included as a project dependency.

## 13. Spring Boot integration

The `holon-vaadin-spring-boot` artifact provides integration with Spring Boot for Vaadin application and view navigator auto configuration.

To enable Spring Boot auto-configuration the following artifact must be included in your project dependencies:

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-vaadin-spring-boot</artifactId>
    <version>5.0.1</version>

The Spring Boot auto-configuration includes the default Spring Boot Vaadin add-on auto configuration features, with the following additional behaviour:

- The configured view navigator will be a Spring `ViewNavigator`

- The `View` authorization support using the `javax.annotation.security.*` annotations is enabled by default

- If Spring Security is available and configured, the `@Secured` annotation based `View` access control is enabled

To disable this auto-configuration feature the `HolonVaadinAutoConfiguration` class can be excluded:

    @EnableAutoConfiguration(exclude={HolonVaadinAutoConfiguration.class})

To disable the Spring Security `@Secured` access control the `HolonVaadinSpringSecurityAutoConfiguration` class can be excluded:

    @EnableAutoConfiguration(exclude={HolonVaadinSpringSecurityAutoConfiguration.class})

### 13.1. Spring Boot starters

The following starter artifacts are available to provide a quick project configuration setup using Maven dependency system:

1. The Holon Vaadin application starter provides the dependencies to the Holon Vaadin Spring Boot integration artifact, in addition to default Holon core Spring Boot starters, the default `spring-boot-starter-web` starter and the `spring-boot-starter-tomcat` to use Tomcat as the embedded servlet container:

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-starter-vaadin</artifactId>
    <version>5.0.1</version>

2. The Holon Vaadin application starter using Undertow, to use Undertow instead of Tomcat as embedded servlet container:

Maven coordinates:

    <groupId>com.holon-platform.vaadin</groupId>
    <artifactId>holon-starter-vaadin-undertow</artifactId>
    <version>5.0.1</version>

## 14. Loggers

By default, the Holon platform uses the SLF4J API for logging. The use of SLF4J is optional: it is enabled when the presence of SLF4J is detected in the classpath. Otherwise, logging will fall back to JUL (`java.util.logging`).

The logger name for the Vaadin module is `com.holonplatform.vaadin`.

## 15. System requirements

### 15.1. Java

The Holon Platform Vaadin module requires Java 8 or higher.

### 15.2. Vaadin

The Holon Platform Vaadin module requires Vaadin 8.1 or higher.