Binding business data to vaadin components

89
Binding business data to Vaadin components Best practices Peter Lehto Senior Vaadin Expert @peter_lehto

Transcript of Binding business data to vaadin components

Binding business data to Vaadin components

Best practices

Peter Lehto Senior Vaadin Expert

@peter_lehto

Application

architecture

Data transfer

Vaadin Containers

Vaadin

Fields

Application Architecture

Deployment

<<UI module>>

CustomerView ProductView

<<UI module>>

CustomerView ProductView

<<Commons module>>

DTOService CustomerDTOCustomerDTO

<<UI module>>

CustomerView ProductView

<<Backend module>>

<<Commons module>>

DTOService CustomerDTO

EntityService

CustomerDTO

DTOServiceBean

Application layers

Client Browser

DevDayUI

Client Browser

DevDayUI

Client Browser

CustomerView ProductView

DevDayUI

DTOService

Client Browser

CustomerView ProductView

DevDayUI

Client Browser

CustomerView ProductView

DTOService

Converters EntityService

DevDayUI

Client Browser

CustomerView ProductView

PersistenceUnit

DTOService

Converters EntityService

DevDayUI

Client Browser

CustomerView ProductView

PersistenceUnit

DTOService

Converters EntityService

@Localpublic interface EntityService {

void storeEntity(AbstractEntity entity);

<E extends AbstractEntity> List<E> getAll(Class<E> entityType);}

@Localpublic interface EntityService {

void storeEntity(AbstractEntity entity);

<E extends AbstractEntity> List<E> getAll(Class<E> entityType);

<E extends AbstractEntity> E getEntityById(long id, Class<E> entityType);

<E extends AbstractEntity> List<E> getPagedEntities(Class<E> entityType,int startIndex, int items, Object[] sortPropertyIds, boolean[] sortStates);

}

@Localpublic interface DTOService {

<DTO extends AbstractDTOWithIdentity> List<DTO> getAllDtos(Class<DTO> dtoType);

}

@Localpublic interface DTOService {

<DTO extends AbstractDTOWithIdentity> List<DTO> getAllDtos(Class<DTO> dtoType);

<DTO extends AbstractDTOWithIdentity> List<DTO> getPagedDtos(Class<DTO> dtoType, int startIndex, int items, Object[] sortPropertyIds, boolean[] sortStates);

<DTO extends AbstractDTOWithIdentity> long getCount(Class<DTO> dtoType);

}

@Localpublic interface DTOService {

<DTO extends AbstractDTOWithIdentity> List<DTO> getAllDtos(Class<DTO> dtoType);

<DTO extends AbstractDTOWithIdentity> List<DTO> getPagedDtos(Class<DTO> dtoType, int startIndex, int items, Object[] sortPropertyIds, boolean[] sortStates);

<DTO extends AbstractDTOWithIdentity> long getCount(Class<DTO> dtoType);

<DTO extends AbstractDTOWithIdentity> DTO getDtoById(long itemId, Class<DTO> dtoType);

<DTO extends AbstractDTOWithIdentity> void storeDto(DTO dto);}

@Statelesspublic class DTOServiceBean implements DTOService, EntityService {

@PersistenceContext(unitName = "devday")private EntityManager entityManager;

…}

Data transfer

DTO (DataTransferObject)

POJO built by DTOService

DTO (DataTransferObject)

POJO built by DTOService

Minimal ondemand data item

DTO (DataTransferObject)

POJO built by DTOService

Minimal ondemand data item

Free from Entity model changes

DTO (DataTransferObject)

POJO built by DTOService

Minimal ondemand data item

Free from Entity model changes

No referenced property loading concerns

DTO (DataTransferObject)

Entity <-> DTO Conversion

UI needs DTOs

Entity <-> DTO Conversion

UI needs DTOs

Backend knows about entities

Entity <-> DTO Conversion

UI needs DTOs

Backend knows about entities

Converter per DTO / usecase type

Entity <-> DTO Conversion

public interface EntityToDTOConverter {

AbstractDTOWithIdentity convertToDTO(AbstractEntity entity);

Class<? extends AbstractEntity> getEntityType();

Class<? extends AbstractDTOWithIdentity> getDTOType();}

public interface EntityToDTOConverter {

AbstractDTOWithIdentity convertToDTO(AbstractEntity entity);

Class<? extends AbstractEntity> getEntityType();

Class<? extends AbstractDTOWithIdentity> getDTOType();}

public interface DTOToEntityConverter {

<DTO extends AbstractDTOWithIdentity, E extends AbstractEntity> E convertToEntity(DTO dto);

Class<? extends AbstractEntity> getEntityType();

Class<? extends AbstractDTOWithIdentity> getDTOType();

}

How to find converter?

Runtime

Instance selection

@Retention(RUNTIME)@Target(TYPE)@Qualifierpublic @Interface DTOType {

}

@Retention(RUNTIME)@Target(TYPE)@Qualifierpublic @Interface DTOType {

Class<? extends AbstractDTO> value(); }

@DTOType(CustomerListingDTO.class)public class CustomerEntityToListingDTOConverter implements EntityToDTOConverter {

@Overridepublic Class<CustomerEntity> getEntityType() {

return CustomerEntity.class;}

@Overridepublic Class<CustomerListingDTO> getDTOType() {

return CustomerListingDTO.class;}

@Overridepublic CustomerListingDTO convertToDTO(CustomerEntity e) { …

}}

public class DTOTypeAnnotationLiteral extends AnnotationLiteral<DTOType> implements DTOType {

private Class<? extends AbstractDTO> dtoType;

public DTOTypeAnnotationLiteral(Class<? extends AbstractDTO> dtoType) {this.dtoType = dtoType;

}

@Overridepublic Class<? extends AbstractDTO> value() {

return dtoType;}

}

protected EntityToDTOConverter findEntityToDTOConverter( Class<? extends AbstractDTO> dtoType) {

Instance<EntityToDTOConverter> converterSelection = converterInstantiator.select(new DTOTypeAnnotationLiteral(dtoType));

if (converterSelection.isAmbiguous()) {// more than one converter for same type exception…

}if (converterSelection.isUnsatisfied()) {

// no converter available exception}

return converterSelection.get();}

DTOService + Converter

No need to change code

DTOService + Converter

No need to change code

Add new converters for new DTO types

DTOService + Converter

No need to change code

Add new converters for new DTO types

Converters via bean discovery

DTOService + Converter

No need to change code

Add new converters for new DTO types

Converters via bean discovery

UI knows and works only with DTOs

DTOService + Converter

Reading data through

Vaadin Containers

Data binding

ContainerItem

Property

In memory containers

In memory containers

IndexedContainer – Basic container that is manually built

In memory containers

HierarchicalContainer – IndexedContainer that supports parent/child relationships

IndexedContainer – Basic container that is manually built

In memory containers

BeanItemContainer – A container that is automatically built from a collection of Java Beans

HierarchicalContainer – IndexedContainer that supports parent/child relationships

IndexedContainer – Basic container that is manually built

100

Browser

Container

100

Server side UI Browser

DB Container

1 000 000 100

Backend Server side UI Browser

DB Container

1 000 000 100

Backend Server side UI Browser

Handled by the table component

Reduce memory footprint with

Lazy loading

LazyQueryContainer

Add-on from Vaadin Directory

LazyQueryContainer

Add-on from Vaadin Directory

Retrieve data by index

LazyQueryContainer

Add-on from Vaadin Directory

Retrieve data by index

Will not expose backend assets

LazyQueryContainer

Grid grid = new Grid();container = new LazyQueryContainer(queryFactory, PRIMARY_KEY_PROPERTY, BATCH_SIZE);grid.setContainerDataSource(container);

public class LazyDTOQuery<DTO extends AbstractDTO> extends AbstractBeanQuery<DTO> {

private Class<DTO> dtoType;private DTOService dtoService;

public LazyDTOQuery(Class<DTO> dtoType, DTOService dtoService, QueryDefinition queryDefinition) {

super(…);}

@Overrideprotected List<DTO> loadBeans(int startIndex, int numItems) {

return dtoService.getPagedDtos(dtoType, startIndex, numItems, getSortPropertyIds(), getSortStates());

}

@Overridepublic int size() {

return dtoService.getCount(dtoType);}

…}

Binding data with

Vaadin Fields

Examples of Fields

Vaadin Fields

Fields are Components with databinding

Vaadin Fields

Fields are Components with databinding

Fields can be bound to properties

Vaadin Fields

Fields are Components with databinding

Fields can be bound to properties

Group of properties is an Item

Vaadin Fields

public class Person {

private String name;private int age;

// Getters and setters omitted

}

public class Person {

private String name;private int age;

// Getters and setters omitted

}

BeanItem<Person> item = new BeanItem<Person>(person);

public class Person {

private String name;private int age;

// Getters and setters omitted

}

BeanItem<Person> item = new BeanItem<Person>(person);

Property ID Type Value

“name” String.class “John Doe”

“age” Integer.class 42

public class Person {

private String name;private int age;

// Getters and setters omitted

}

BeanItem<Person> item = new BeanItem<Person>(person);

Property ID Type Value

“name” String.class “John Doe”

“age” Integer.class 42

Separate Field value from Property value with

Buffering

Buffering

setPropertyDatasource(property);

Buffering

setPropertyDatasource(property);

setBuffered(true);

Buffering

setPropertyDatasource(property);

setBuffered(true);

commit();

Buffering

setPropertyDatasource(property);

setBuffered(true);

commit();

discard();

Buffering

Buff

eri

ng

Data source

UI Logic

AbstractField

Button

Browser

Buff

eri

ng

Data source

UI Logic

AbstractField

Button

Browser

TextField value change

Buff

eri

ng

Data source

UI Logic

AbstractField

Button

Browser

TextField value change

Save button pressed

Buff

eri

ng

Data source

UI Logic

AbstractField

Button

Browser

TextField value change

Save button pressed

ClickEvent

commit()

Buff

eri

ng

Data source

UI Logic

AbstractField

Button

Browser

TextField value change

Save button pressed

ClickEvent

commit()

Buff

eri

ng

Data source

UI Logic

AbstractField

Button

Browser

TextField value change

Save button pressed

ClickEvent

FieldGroup combining many Fields together

(used to be Form)

setItemDataSource(Item item)

?What is the difference between these two method calls?

comboBox. setPropertyDataSource(property);

comboBox. setContainerDataSource(container);