KEMBAR78
Workshop: Building Vaadin add-ons | PDF
Building Vaadin add-ons
Sami Ekblad, Vaadin
@samiekblad
at are
Wh
d-ons?
ad
add-on

architectu
re
dev
tools
GWT

JS

add-on

add-on
packaging
and distribution
✎

this is a

workshop
What we do here
Eclipse Kepler - eclipse.org
Vaadin plugin for Eclipse - vaadin.com/eclipse
Jetty Server - run-Jetty-run plugin
New Vaadin project - testing and development
DatePicker - simple GWT or JavaScript add-on
... or something else.
?

what is a
Vaadin

add-on
java

html
Javascript
handling

Cross-browser
issues

Browser

Typical Java EE
web application:
AJAX request
handling &
protocol

Security

UI
business logic

View config XMLs

JavaScript +
Server-side JSF
(or something)

Server
Backend API
Javascript
handling

Browser

Cross-browser
issues

d
e
l n
d i
n d
a a
H Va
y
b

AJAX request
handling &
protocol

Security

UI
business logic

View config XMLs

Server
Backend API

Vaadin
Focus on
business logic
Client-server UI components
“UI Component”
• Button, Table, Tree, ...
• Server-side data
• Full Java API

HTTP(S)

“Widget”
• Client-side peer for the
component
• Runs on JavaScript

Java

Java

• Compiled with JDK

• Google Web Toolkit
This is add-on
HTTP(S)

“UI Component”
• Button, Table, Tree, ...
• Server-side data
• Full Java API

Java
• Compiled with JDK

“Widget”
• Client-side peer for the
component
• Runs on JavaScript

Java

Add-on JAR file

• Google Web Toolkit
Vaadin

Directory
Vaadin Directory
Find, download and rate add-ons
Channel to all Vaadin developers
Automatic Maven integration
Webcam
Webcam allows you to capture
images from the web camera.

webcam.addCaptureSucceededListener(new CaptureSucceededListener() {
@Override
public void captureSucceeded(CaptureSucceededEvent event) {
Image img = new Image("Captured image", new FileResource(
targetFile));
img.setWidth("200px");
layout.addComponent(img);
}
});
ReCaptcha
A wrapper component for ReCaptcha.
Recaptcha4j used for the server side
validation of the captcha.

ReCaptcha captcha = new ReCaptcha(
MY_PRIVATE_KEY,
MY_PUBLIC_KEY,
new ReCaptchaOptions() {{
theme = "white";
}}
);
layout.addComponent(captcha);
GoogleMaps
Enables Google Maps support in Vaadin
7 projects.

GoogleMap googleMap = new GoogleMap(new LatLon(60.440963, 22.25122),
10.0, apiKey);
googleMap.setSizeFull();
googleMap.addMarker("DRAGGABLE: Paavo Nurmi Stadion", new LatLon(
60.442423, 22.26044), true, "VAADIN/1377279006_stadium.png");
kakolaMarker = googleMap.addMarker("DRAGGABLE: Kakolan vankila",
new LatLon(60.44291, 22.242415), true, null);
googleMap.addMarker("NOT DRAGGABLE: Iso-Heikkilä", new LatLon(
60.450403, 22.230399), false, null);
googleMap.setMinZoom(4.0);
googleMap.setMaxZoom(16.0);
Spring stuff
This add-on contains classes
that add some missing "glue"
between Vaadin and Spring.

<!-- Activate Spring annotation support -->
<context:annotation-config/>
<!-- Example of an application-specific bean which gets
created and autowired when the
application starts and destroyed when the application stops -->
<bean class="com.example.MyApplicationBean"/>
<!-- This makse the Vaadin application instance itself available in,
and autowired by, this context -->
<bean class="org.dellroad.stuff.vaadin.ContextApplicationFactoryBean"
p:autowire="true"/>
OAuth Popup
Authorize the Vaadin application to do things on the
users' behalf on various services such as Facebook,
Twitter, etc.
OAuthPopupButton ob = new TwitterButton(TW_KEY, TW_SECRET);
ob.addOAuthListener(new OAuthListener() {
@Override
public void authSuccessful(String accessToken,
String accessTokenSecret) {
Notification.show("Authorized");
// TODO: do something with the access token
}
@Override
public void authDenied(String reason) {
Notification.show("Authorization denied");
}
});
Scaladin
Scaladin makes easier to use Vaadin Framework with
Scala programming language.

class ScaladinExampleApplication extends
Application("Scaladin Example") {
override val main = new VerticalLayout {
add(new Button {
caption = "Click me!"
icon = new ThemeResource("../runo/icons/16/globe.png")
clickListeners += { mainWindow.showNotification("Hello World!")
})
}
}
LeapGestures
Basic Leapmotion gestures API for Vaadin.

LeapGestures g = LeapGestures.extend(this);
g.addSwipeDownListener(new SwipeDownListener() {
@Override
public void onSwipeDown(SwipeDownArgs args) {
layout.addComponent(new Label("swipe down"));
}
});
Widgets - the most common add-ons
Extensions - invisible functionality
Data - integration to the backend
Tools - additional tools and components
Misc - something else
planning

an add-on?
2 types of add-ons
1. Internal add-ons
Used in foundation / platform

2. public open-source
Shared with community
Idea
=
how it is used (UX)
+
how it works (Tech)
Aim for multilayered
design that lets your
users (developers)
change behavior of
your component
Demo application
should include all features
and serve as example
for your users
Java
components
Widgets - the most common add-ons

Vaadin Charts

PopupButton

ConfirmDialog

GWT Graphics

Calendar

Switch
Logical structure
Client

Communication

Server

something.js
GWT

MyJSNI.java

MyWidget.java

Connector
RPC + state

MyComponent.java

MyTestUI.java
Vaadin
Java package structure
org.company.myaddon
MyComponent.java

MyTestUI.java

org.company.myaddon.client
Connector
RPC + state

MyWidget.java

MyJSNI.java

org.company.myaddon.client.public
something.js
Extensions - invisible add-ons (or not)
final Refresher refresher = new Refresher();
refresher.addListener(new DatabaseLazyLoader());
addExtension(refresher);
Data - integration to the backend
»

getting started

development
tools
Tools for add-on development
Browser
developer
tools
Java
IDE

Java EE
Server

Google Chrome
Firefox
Safari

NetBeans 7.4 (+ Vaadin plugin)
Eclipse Kepler (+Vaadin and Jetty plugin)

Tomcat 7
Jetty 8
Maven artifact for add-on
mvn -DarchetypeGroupId=com.vaadin 
-DarchetypeArtifactId=vaadin-archetype-widget
-DarchetypeVersion=7.1.9 
-DgroupId=org.vaadin.se 
-DartifactId= myaddon 
-DComponentClassName=MyAddon 
-Dversion=1.0-SNAPSHOT 
-Dpackage=org.vaadin.se.myaddon 
archetype:generate
Eclipse plugin wizards
GWT

creating a
GWT widget

add-on
DatePicker component
“The goal of this exercise is to practice the usage of
RPC and shared state. In this exercise, we will take
an existing GWT widget and make it compatible
with server-side Vaadin applications.”
com.google.gwt.user.datepicker.client. DatePicker
DatePicker structure
Client

Communication

Server

GWT
DatePicker

Connector
RPC + state

DatePicker
Component.java

MyTestUI.java
Vaadin
1. Create a new Vaadin7 project called DatePicker
2. Create a new Vaadin 7 widget using the ”fullfledged”
template, call your widget DatePickerComponent
3. In the server-side component, override getState to
return a DatePickerState
4. Remove the client RPC interface
5. In the server RPC interface, define one method,
dateChanged(Date date)
Eclipse plugin wizards

New project

New widget

Choose
“Full fledged”
SuperDevMode
client-side debugging
SuperDevMode setup
Project
properties view

<!-- Enabled by default: add-linker name="xsiframe"/ -->
<set-configuration-property name="devModeRedirectEnabled"
value="true" />

<!-- also add compiler option -->
<set-property name="user.agent" value="safari"/>

.gwt.xml
SuperDevMode runtime
SuperDevMode code server for MyAddonProject.launch
Visit http://localhost:9876/

Start
code server

Debug as » Debug on server
Visit http://localhost:8080/MyAddOnProject?debug

Run
application in
SuperDevMode
6. The state object should have a field for the selected date
7. Set a default value for the date
8. Implement the server RPC in the server-side component.The
dateChanged method should update the selected date in state
9. The connector should create a DatePicker widget
10. The connector should register itself as a
ValueChangeHandler<Date> to the widget, in order to listen to
the selected date
11. State changes should be passed to the widget
Client-side classes
DatePickerConnector
DatePickerClientRpc
DatePickerState
Server-side classes
DatePickerComponent
MyTestUI
GWT widget theme
to use the
default
GWT theme

Include the following to the .gwt.xml
<inherits name="com.google.gwt.user.theme.standard.Standard" />
JSNI classes
Java to JavaScript:
public static native void alert(String msg) /*-{
$wnd.alert(msg);
}-*/;

JavaScript to Java:
// Call instance method instanceFoo() on x
x.@org.vaadin.se.myaddon.MyJSNI::myMethod(Ljava/lang/String;)(s);
js

JavaScript

shortcut
Logical structure
something.js
GWT

MyJSNI.java

MyWidget.java

RPC
(+state)

MyComponent.java

MyTestUI.java
Vaadin
JavaScript components
something.js
GWT

JSNI.java

JSWidget.java

RPC
(+state)

MyComponent.java

MyTestUI.java
Vaadin
JavaScript shortcut
org.company.myaddon
something.js

MyComponent.java

MyTest.java
JavaScript components

AbstractJavaScriptComponent

something.js
MyComponent.java
integration.js
Eclipse plugin wizard

New project

New class
Server code
@JavaScript({"three.min.js",
"cube_integration.js"})
public class Cube
extends AbstractJavaScriptComponent {
!
!
!
!

!
!
!
!

public Cube() {
! setWidth("200px");
! setHeight("200px");
}

!
!
!
!
!
!
!

!
!
!
!
!
!
!

public CubeState getState() {
! return (CubeState) super.getState();
}
public boolean isAnimating() {
! return getState().animate;
}

! ! public void stop() {
! ! ! getState().animate = false;
! ! }
!
!
!
!

! public void start() {
! ! getState().animate = true;!! !
! }
!

public class CubeState
extends JavaScriptComponentState {
! public boolean animate = false;
}
Client integration JavaScript
window.com_example_threejs_Cube = function() {
var element = this.getElement();

// This is Vaadin callback on state changes
this.onStateChange = function() {
! if (this.getState().animate) {
! this.start();
!
! else {
}
! this.stop();
!
!
}
}
// React to resize events
this.addResizeListener(this.getElement(), this.onResize);
// ...
}
JavaScript not found
Could not initialize JavaScriptConnector because no
JavaScript init function was found. Make sure one of
these functions are defined:
• com_example_threejsaddon_Cube
• com_vaadin_ui_AbstractJavaScriptComponent
• com_vaadin_ui_AbstractComponent
• com_vaadin_server_AbstractClientConnector
#

packaging

add-ons
Export add-on jar
Add-on versions follow semver.org
New add-on version (start with 1.0.0)

Major

when you make incompatible API changes

when you add functionality

Minor

Patch

Do not break backward compatibility

when you make backwards-compatible bug fixes
No new features
Naming

Unique name
Vaadin XYZ
XYZ for Vaadin
[Use some time for the name, it is really really important]
Add-on jar
Naming

Component class name: MyAddon.java
Add-on Jar-name: myaddon-1.0.0.jar

WebContent/META-INF/MANIFEST.MF:

JAR manifest

Vaadin-Package-Version: 1
Vaadin-Widgetsets: com.example.myaddon.MyAddonWidgetset

META-INF/maven/com.example.myaddon/myaddon/pom.xml

pom.xml

Specify external Maven dependencies
*

publishing

add-ons
Vaadin Directory
1. Create user account to Vaadin.com
2. Upload your jar
3. Edit the add-on information
Publish add-ons in Directory
Good
description

Links and
documentation
Demo is
worth
a thousand
words

Be descriptive and think of SEO.
Make screenshots and screencasts.

Example code, issue tracking, discussion
Publish sources (GitHub is good)

Show how it works. Remember code samples.
Works as test and validation for your add-on
★★★★⭐︎

what makes a

good add-on?
Add-on ideas
Start from
yourself

There is aready one user for something that you need.
Common patterns and needs.
Combine client and server

Generalize

Reuse existing JavaScript and GWT widgets.
Abstract functionality: Java API is your product
Fix bugs

Maintain

Follow discussion
Further reading
http://j.mp/vaadin-addons
https://vaadin.com/blog/-/blogs/vaadin-js-and-dom-initialization-order
https://vaadin.com/blog/-/blogs/an-interview-with-an-add-on-wizard-johan-anas
https://vaadin.com/directory/help/creating-vaadin-add-ons

Workshop: Building Vaadin add-ons