Date post: | 22-Jan-2018 |
Category: |
Software |
Upload: | peter-lehto |
View: | 242 times |
Download: | 2 times |
5
S T O R Y A N D P H I L O S O P H Y
Software is eating the world and what most of us see of it is the user interface. The user
interface has become the key component of how the users experience the business
behind it. Competition is lost or won due to user experience. Simplicity is king and the
users get frustrated by anything ugly, slow or not working on the device they happen to
use at the time. We at Vaadin fight for simplicity and invite everyone to join this fight.
Together we want to build a user interface that puts a smile on the user’s face.
Vaadin is the technology that empowers developers to build the best web-apps for
business purposes. Our priority over everything else is developer productivity because
we believe that by simplifying the developer experience and saving the developer’s
time, they are best able to focus on building great user interfaces.
Our brand is what we want everyone to think about us. When everyone - both us and
the people around us - have a consistent understanding of what Vaadin is and what we
stand for, it enables that image to spread and amplify. This book defines what we want
that image to be. It defines what the Vaadin brand is.
I hope that You are as excited and proud of living and breathing the Vaadin brand as
I am. You are the one who is shaping what everyone thinks about Vaadin - using this
brand as a tool and a guideline every day.
Let’s fight for simplicity for both the users and the developers!
Joonas Lehtinen
Founder & CEO
Vaadin
I N T R O D U C T I O N
@peter_lehto
D I Y O U R U I
Session’s content
Session’s content
• What Dependency Injection, Why and How?
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
• Tips and Tricks for Springifying your Vaadin app
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
• Tips and Tricks for Springifying your Vaadin app
W h a t D e p e n d e n c y I n j e c t i o n ?
WHAT DI? private Grid<Customer> grid;
INSTEAD OFNEW private Grid<Customer> grid;
protected void init(VaadinRequest request) { grid = new Grid<>(); grid.setSizeFull();
SAY@AUTOWIRED
@Autowiredprivate Grid<Customer> grid;
protected void init(VaadinRequest request) { grid.setSizeFull();
@Beanpublic Grid<Customer> configureBeanGrid() {BEAN
CONFIG
@Beanpublic Grid<Customer> configureBeanGrid() {Grid<Customer> grid = new Grid<>();
BEANCONFIG
@Beanpublic Grid<Customer> configureBeanGrid() {Grid<Customer> grid = new Grid<>();grid.addColumn(Customer::getFirstName).setCaption("First name");grid.addColumn(Customer::getLastName).setCaption("Last name");
BEANCONFIG
@Beanpublic Grid<Customer> configureBeanGrid() {Grid<Customer> grid = new Grid<>();grid.addColumn(Customer::getFirstName).setCaption("First name");grid.addColumn(Customer::getLastName).setCaption("Last name");
return grid;}
BEANCONFIG
Dependency Injection (DI) is a runtime mechanism
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Instead with DI a special DI container takes care of the object lifecycle management
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Instead with DI a special DI container takes care of the object lifecycle management where clients reference managed and possibly shared objects.
W h y ?
• High Abstraction
• High Abstraction• Loose coupling
• High Abstraction• Loose coupling• Dependency inversion
• High Abstraction• Loose coupling• Dependency inversion• Highly cohesive modules
• High Abstraction• Loose coupling• Dependency inversion• Highly cohesive modules• Deployment time config
H o w ?
HIGHABSTRACTION
interface GadgetConfiguration
HIGHABSTRACTION
interface GadgetConfiguration
interface Gadget<C extends GadgetConfiguration>
HIGHABSTRACTION
interface GadgetConfiguration
interface Gadget<C extends GadgetConfiguration>
interface ConfigurationDialog<C extends GadgetConfiguration>
HIGHABSTRACTION
class NotesConfiguration implements GadgetConfiguration {}
HIGHABSTRACTION
class NotesConfiguration implements GadgetConfiguration {}
class NotesGadget implements Gadget<NotesConfiguration> {}
HIGHABSTRACTION
class NotesConfiguration implements GadgetConfiguration {}
class NotesGadget implements Gadget<NotesConfiguration> {}
class NotesConfigurationDialog implements ConfigurationDialog<NotesConfiguration> {}
HIGHABSTRACTION
class NotesConfiguration implements GadgetConfiguration {}
@Componentclass NotesGadget implements Gadget<NotesConfiguration> {}
@Componentclass NotesConfigurationDialog implements ConfigurationDialog<NotesConfiguration> {}
APPLICATIONCONTEXT
String[] getBeanNamesForType(Class<?> type);
String[] getBeanNamesForType(ResolvableType type);
Map<String, T> getBeansOfType(Class<T> type);
Map<String, Object> getBeansWithAnnotation(Class<?> annot);
Object getBean(String);
T getBean(String, Class<T> type);
LOOSECOUPLING interface MainMenu { }
• Define abstraction
LOOSECOUPLING interface MainMenu { }
@Componentclass DefaultMainMenu implements MainMenu {}• Define abstraction
• Define Implementations
LOOSECOUPLING interface MainMenu { }
@Componentclass DefaultMainMenu implements MainMenu {}
@Componentclass ResponsiveMainMenu implements MainMenu {}
• Define abstraction
• Define Implementations
DEPENDENCYINVERSION
@Autowiredprivate MainMenu mainMenu;
• Define abstraction
• Define Implementations
• Depend on Abstraction,not concrete type -> Depency Inversion
@Componentpublic class DefaultMainMenu implements MainMenu { … }
D e f i n i n g a B e a n
@Component@UIScopepublic class DefaultMainMenu implements MainMenu { … }
D e f i n i n g a B e a n
@Configurationpublic class ComponentConfiguration {
@Bean @Primary @UIScope public MainMenu provideDefaultMenu { return new DefaultMainMenu(); }
… w i t h @ C o n f i g u r a t i o n
@Bean @Responsive
@UIScope public MainMenu provideResponsiveMenu {
return new ResponsiveMainMenu(); }}
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
• Tips and Tricks for Springifying your Vaadin app
Automatic discoveryand lookup
UI AS BEAN@SpringUIpublic class VaadinUI extends UI {
path attribute forURL binding
UI AS BEAN
@SpringUI(path = "app")public class VaadinUI extends UI {
@SpringUIpublic class VaadinUI extends UI {
localhost:8080/context
UI AS BEAN
localhost:8080/context/app @SpringUI(path = "app")public class VaadinUI extends UI {
@SpringUIpublic class VaadinUI extends UI {
HorizontalLayoutContentAreaMenu
View1
View2
View3
HorizontalLayoutView1Menu
View1
View2
View3
HorizontalLayoutView2Menu
View1
View2
View3
HorizontalLayoutView3Menu
View1
View2
View3
Implement View andannotate with @SpringView
VIEW AS BEAN@SpringView(name = "customers")public class CustomerView extends VerticalLayout implements View {
Wrapper for ViewComponent in UI
VIEWDISPLAY@SpringViewDisplaypublic class DevDayViewDisplay extends VerticalSplitPanel implements ViewDisplay {
S p r i n g V i e w P r o v i d e r
SPRING NAVIGATOR
@Autowiredprivate Navigator navigator;
navigator.navigateTo(“customers”);
N a v i g a t o r
V i e w b e a n d i s c o v e r y b y @ S p r i n g V i e w
SPRING NAVIGATOR
public interface ViewAccessControl;public interface ViewInstanceAccessControl;
C o n t r o l l i n g a c c e s s t o v i e w s
COMPONENTSAS
BEANS
@Autowiredprivate Grid<Customer> grid;
DEMO
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
• Tips and Tricks for Springifying your Vaadin app
H o w a r e t h e b e a n i n s t a n c e s m a n a g e d ?
WITH SCOPES
@ S e s s i o n S c o p e
WITH SCOPES
@Autowiredprivate User currentUser;
@ S e s s i o n S c o p e
@ S e s s i o n S c o p e@ Va a d i n S e s s i o n S c o p e
WITH SCOPES
@ S e s s i o n S c o p e@ Va a d i n S e s s i o n S c o p e
@ U I S c o p e
WITH SCOPES
public interface MainMenu { … }
@Autowiredprivate MainMenu mainMenu;
@Component@UIScopepublic class DefaultMainMenu implements MainMenu { … }
@ U I S c o p e
@ S e s s i o n S c o p e@ Va a d i n S e s s i o n S c o p e
@ U I S c o p e@ V i e w S c o p e
WITH SCOPES
@Component@ViewScopepublic class NotesGadget {
@Autowired private EventBus.ViewEventBus eventBus;
@ V i e w S c o p e
@ S e s s i o n S c o p e@ Va a d i n S e s s i o n S c o p e
@ U I S c o p e@ V i e w S c o p e
@ R e q u e s t S c o p e
WITH SCOPES
public interface HttpRequestStopWatch { … }
@ R e q u e s t S c o p e
@SessionScope
@SessionScope@VaadinSessionScope
@SessionScope@VaadinSessionScope
@UIScope
@SessionScope@VaadinSessionScope
@UIScope @ViewScope
@SessionScope
@ApplicationScoped@SessionScope
@Vaadin SessionScope
@Vaadin SessionScope
@Vaadin SessionScope
@SessionScope
@Vaadin SessionScope
@Vaadin SessionScope
@Vaadin SessionScope
@UI Scope
@UI Scope
@UI Scope
@UI Scope
@UI Scope
@UI Scope
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@UI Scope
@UI Scope
@UI Scope
@UI Scope
@UI Scope
@UI Scope
@SessionScope
@Vaadin SessionScope
@Vaadin SessionScope
@Vaadin SessionScope
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
• Tips and Tricks for Springifying your Vaadin app
E v e n t B u s@Component@ViewScopepublic class DataEditor<DTO> {
}
E v e n t B u s@Component@ViewScopepublic class DataEditor<DTO> {
@Autowiredprivate EventBus.ViewEventBus eventBus;
…}
E v e n t B u s@Component@ViewScopepublic class DataEditor<DTO> {
@Autowiredprivate EventBus.ViewEventBus eventBus;
protected void onSaveClicked() {eventBus.publish(this, new EditorSaveEvent());
}…
}
@Component@ViewScopepublic class DataTable<DTO> extends Grid<DTO> {
@Autowiredprivate EventBus.ViewEventBus eventBus;
}
@Component@ViewScopepublic class DataTable<DTO> extends Grid<DTO> {
@Autowiredprivate EventBus.ViewEventBus eventBus;
@PostConstructprotected void initialize() {eventBus.subscribe(this);
}
}
@Component@ViewScopepublic class DataTable<DTO> extends Grid<DTO> {
@Autowiredprivate EventBus.ViewEventBus eventBus;
@PostConstructprotected void initialize() {eventBus.subscribe(this);
}
@EventBusListenerMethodprotected void onSaveEvent(EditorSaveEvent e) {getDataProvider().refreshAll();
}}
Va a d i n I 1 8 N S u p p o r t
@EnableI18N
Va a d i n I 1 8 N S u p p o r t
@EnableI18N
@BeanI18N i18n() { return new I18N(context);}
Va a d i n I 1 8 N S u p p o r t
@EnableI18N
@BeanI18N i18n() { return new I18N(context);}
@BeanCompositeMessageSource messageSource() { return new CompositeMessageSource(context);}
Va a d i n I 1 8 N S u p p o r t
@BeanMessageProvider provideTranslations() { return new ResourceBundleMessageProvider (“com.foo.path.to.bundle”, "UTF-8");}
Session’s content
• What Dependency Injection, Why and How?
• Vaadin UI, View and components as Beans
• Instances and Scopes
• EventBus and other DI Extensions
• Tips and Tricks for Springifying your Vaadin app
S e t t i n g u p m e n u a u t o m a t i c a l l y
@MenuDefinition(icon=, name=, order=)@SpringView(name=“customers”)public class CustomerViewBean implements View… {
…}
S e t t i n g u p m e n u a u t o m a t i c a l l y private void findAndPopulateMenuItems() { List<String> beanNames = Arrays.asList(context. getBeanNamesForAnnotation(MenuDefinition.class));
}
S e t t i n g u p m e n u a u t o m a t i c a l l y private void findAndPopulateMenuItems() { List<String> beanNames = Arrays.asList(context. getBeanNamesForAnnotation(MenuDefinition.class));
Map<String, MenuDefinition> definitionsToNames = beanNames.stream(). collect(Collectors.toMap(Function.identity(), beanName -> context.findAnnotationOnBean(beanName, MenuDefinition.class)));
Map<String, SpringView> viewsToNames = beanNames.stream(). collect(Collectors.toMap(Function.identity(), beanName -> context.findAnnotationOnBean(beanName, SpringView.class)));
}
S e t t i n g u p m e n u a u t o m a t i c a l l y private void findAndPopulateMenuItems() { List<String> beanNames = Arrays.asList(context. getBeanNamesForAnnotation(MenuDefinition.class));
Map<String, MenuDefinition> definitionsToNames = beanNames.stream(). collect(Collectors.toMap(Function.identity(), beanName -> context.findAnnotationOnBean(beanName, MenuDefinition.class)));
Map<String, SpringView> viewsToNames = beanNames.stream(). collect(Collectors.toMap(Function.identity(), beanName -> context.findAnnotationOnBean(beanName, SpringView.class)));
beanNames.forEach(beanName -> { MenuDefinition menuDefinition = definitionsToNames.get(beanName); SpringView viewDefinition = viewsToNames.get(beanName);
addMenuItem(menuDefinition.name(), menuDefinition.icon(), viewDefinition.name()); }); }
Lessons learned
Lessons learned• DI is a powerful mechanism to decouple code
Lessons learned• DI is a powerful mechanism to decouple code
• Following DI almost certainly guarantees that best practices are followed
Lessons learned• DI is a powerful mechanism to decouple code
• Following DI almost certainly guarantees that best practices are followed
• Vaadin supports DI with Spring and CDI, both through their own integration add-ons
Lessons learned• DI is a powerful mechanism to decouple code
• Following DI almost certainly guarantees that best practices are followed
• Vaadin supports DI with Spring and CDI, both through their own integration add-ons
• Lot of Spring functionality is based on Beans
Lessons learned• DI is a powerful mechanism to decouple code
• Following DI almost certainly guarantees that best practices are followed
• Vaadin supports DI with Spring and CDI, both through their own integration add-ons
• Lot of Spring functionality is based on Beans
• Structuring Vaadin app with Bean approach can provide great flexibility and robustness
@peter_lehto
T H A N K Y O U !