workshop: building vaadin add-ons

77
Building Vaadin add-ons Sami Ekblad, Vaadin @samiekblad

Upload: sami-ekblad

Post on 10-May-2015

1.429 views

Category:

Technology


7 download

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

Building Vaadin add-ons

Sami Ekblad, Vaadin@samiekblad

What are

add-ons?

add-onarchitecture

devtools

GWTadd-on

JSadd-on

packagingand 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

DatePicker - simple GWT or JavaScript add-on

... or something else.

New Vaadin project - testing and development

what is a

Vaadin add-on?

htmljava

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

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

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 multilayereddesign that lets yourusers (developers)change behavior ofyour component

Demo applicationshould include all featuresand serve as examplefor your users

Javacomponents

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);

Data - integration to the backend

getting started

developmenttools»

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

Eclipse plugin wizards

creating a GWT widget

add-onGWT

“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)

Eclipse plugin wizards

New project New widgetChoose

“Full fledged”

SuperDevModeclient-side debugging

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

DatePickerConnectorDatePickerClientRpcDatePickerState

Client-side classes

DatePickerComponentMyTestUI

Server-side classes

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:

JavaScript

shortcutjs

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

something.js MyComponent.java MyTest.java

JavaScript shortcut

org.company.myaddon

JavaScript components

AbstractJavaScriptComponent

MyComponent.java

something.js

integration.js

Eclipse plugin wizard

New project New class

@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

packaging

add-ons#

Export add-on jar

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

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

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

what makes a

good 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