workshop: building vaadin add-ons
DESCRIPTION
Workshop on how to build Vaadin Add-ons. We introduce two styles of building Vaadin add-on components for Vaadin: integrating an existing GWT widget (DatePicker), and integrating an existing JavaScript library (three.js).TRANSCRIPT
What we do here
Eclipse Kepler - eclipse.org
Vaadin plugin for Eclipse - vaadin.com/eclipse
Jetty Server - run-Jetty-run plugin
DatePicker - simple GWT or JavaScript add-on
... or something else.
New Vaadin project - testing and development
Browser
Javascripthandling
Cross-browser issues
Typical Java EE web application:
JavaScript + Server-side JSF (or something)
Server
UI business logic
View config XMLs
Backend API
AJAX request handling & protocol
Security
Vaadin
Focus on business logic
Browser
Javascripthandling
Cross-browser issues
Server
UI business logic
View config XMLs
Backend API
AJAX request handling & protocol
Security
Javascripthandling
Cross-browser issues
View config XMLs
AJAX request handling & protocol
Security
Handled
by Vaadin
Client-server UI components
“UI Component”• Button, Table, Tree, ...• Server-side data• Full Java API
“Widget”• Client-side peer for the
component• Runs on JavaScript
HTTP(S)
Java
• Google Web Toolkit
Java
• Compiled with JDK
This is add-on
“UI Component”• Button, Table, Tree, ...• Server-side data• Full Java API
“Widget”• Client-side peer for the
component• Runs on JavaScript
HTTP(S)
Java
• Google Web Toolkit
Java
• Compiled with JDK
Add-on JAR file
Vaadin Directory
Channel to all Vaadin developers
Find, download and rate add-ons
Automatic Maven integration
Webcam allows you to capture images from the web camera.
Webcam
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); } });
A wrapper component for ReCaptcha.Recaptcha4j used for the server side validation of the captcha.
ReCaptcha
ReCaptcha captcha = new ReCaptcha( MY_PRIVATE_KEY, MY_PUBLIC_KEY, new ReCaptchaOptions() {{ theme = "white"; }});layout.addComponent(captcha);
Enables Google Maps support in Vaadin 7 projects.
GoogleMaps
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);
This add-on contains classes that add some missing "glue" between Vaadin and Spring.
Spring stuff
<!-- 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"/>
Authorize the Vaadin application to do things on the users' behalf on various services such as Facebook, Twitter, etc.
OAuth Popup
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 makes easier to use Vaadin Framework with Scala programming language.
Scaladin
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!") } }) }}
Basic Leapmotion gestures API for Vaadin.
LeapGestures
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
2 types of add-ons
1. Internal add-ons Used in foundation / platform
2. public open-source Shared with community
Widgets - the most common add-ons
ConfirmDialog
Vaadin Charts PopupButton Calendar
GWT Graphics Switch
GWT
Vaadin
something.js
MyJSNI.java
ConnectorRPC + state
MyComponent.javaMyWidget.java
MyTestUI.java
Logical structureClient Communication Server
MyJSNI.java
MyComponent.java
MyWidget.java
MyTestUI.java
Java package structure
org.company.myaddon
org.company.myaddon.client
org.company.myaddon.client.public
something.js
ConnectorRPC + state
Extensions - invisible add-ons (or not)
final Refresher refresher = new Refresher();refresher.addListener(new DatabaseLazyLoader());addExtension(refresher);
Tomcat 7 Jetty 8
Tools for add-on development
Java EEServer
JavaIDE
NetBeans 7.4 (+ Vaadin plugin) Eclipse Kepler (+Vaadin and Jetty plugin)
Browserdeveloper
tools
Google ChromeFirefoxSafari
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
“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.”
DatePicker component
DatePickercom.google.gwt.user.datepicker.client.
GWT
Vaadin
ConnectorRPC + state
DatePickerComponent.javaDatePicker
MyTestUI.java
DatePicker structureClient Communication Server
1. Create a new Vaadin7 project called DatePicker2. 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)
SuperDevMode setup
<!-- 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
Project properties view
SuperDevMode runtime
Start code serverVisit http://localhost:9876/
SuperDevMode code server for MyAddonProject.launch
Run application in
SuperDevMode
Debug as » Debug on server
Visit http://localhost:8080/MyAddOnProject?debug
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 widget10. The connector should register itself as a ValueChangeHandler<Date> to the widget, in order to listen to the selected date11. State changes should be passed to the widget
to use the default
GWT theme
Include the following to the .gwt.xml
GWT widget theme
<inherits name="com.google.gwt.user.theme.standard.Standard" />
JSNI classes
public static native void alert(String msg) /*-{ $wnd.alert(msg);}-*/;
// Call instance method instanceFoo() on x [email protected]::myMethod(Ljava/lang/String;)(s);
Java to JavaScript:
JavaScript to Java:
GWT
Vaadin
something.js
MyJSNI.java
RPC(+state)
MyComponent.javaMyWidget.java
MyTestUI.java
Logical structure
GWT
Vaadin
something.js
JSNI.java
RPC(+state)
MyComponent.javaJSWidget.java
MyTestUI.java
JavaScript components
@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;!! !! ! }! !}
Server codepublic class CubeState extends JavaScriptComponentState {
! public boolean animate = false;
}
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);
// ... }
Client integration JavaScript
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
JavaScript not found
Add-on versions follow semver.org
Minorwhen you add functionality
Patch
MajorNew add-on version (start with 1.0.0)
when you make incompatible API changes
Do not break backward compatibility
when you make backwards-compatible bug fixes
No new features
Unique name
Vaadin XYZ
XYZ for Vaadin
[Use some time for the name, it is really really important]
Naming
Add-on jar
JAR manifest
WebContent/META-INF/MANIFEST.MF:
pom.xml
Vaadin-Package-Version: 1Vaadin-Widgetsets: com.example.myaddon.MyAddonWidgetset
META-INF/maven/com.example.myaddon/myaddon/pom.xml
NamingAdd-on Jar-name: myaddon-1.0.0.jar
Component class name: MyAddon.java
Specify external Maven dependencies
Vaadin Directory
1. Create user account to Vaadin.com
2. Upload your jar
3. Edit the add-on information
Publish add-ons in Directory
Gooddescription
Be descriptive and think of SEO.
Links anddocumentation
Demo isworth
a thousand words
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
Add-on ideas
Start fromyourself
There is aready one user for something that you need.
Common patterns and needs.
MaintainFix bugs
Follow discussion
Generalize Reuse existing JavaScript and GWT widgets.
Abstract functionality: Java API is your product
Combine client and server
https://vaadin.com/blog/-/blogs/vaadin-js-and-dom-initialization-order
Further reading
https://vaadin.com/blog/-/blogs/an-interview-with-an-add-on-wizard-johan-anas
https://vaadin.com/directory/help/creating-vaadin-add-ons
http://j.mp/vaadin-addons