summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatti Tahvonen <matti@vaadin.com>2016-02-29 17:14:16 +0200
committerTeemu Suo-Anttila <teemusa@vaadin.com>2016-03-08 13:59:14 +0200
commit96da1ff946c0d93deadcc04146b70d217c78b393 (patch)
tree87d77d77461484e9d6fa2d9da016d7f1c80e95e2
parent53c2f775fc6a5a8649b698dc47695cf4f0f7d0e1 (diff)
downloadvaadin-framework-96da1ff946c0d93deadcc04146b70d217c78b393.tar.gz
vaadin-framework-96da1ff946c0d93deadcc04146b70d217c78b393.zip
Added tutorial to documentation
Change-Id: I9d182f2c96f73224c52ed62693b18511eac7e11a
-rw-r--r--documentation/img/createMavenProject.jpgbin0 -> 118741 bytes
-rw-r--r--documentation/img/debugAsMavenBuild.jpgbin0 -> 192069 bytes
-rw-r--r--documentation/img/debugAsMavenBuild2.jpgbin0 -> 151225 bytes
-rw-r--r--documentation/img/debugAsMavenBuildAddSources.jpgbin0 -> 151843 bytes
-rw-r--r--documentation/img/debugInBreakPointVariable.jpgbin0 -> 214112 bytes
-rw-r--r--documentation/img/eclipseWithoutJdkError.jpgbin0 -> 181452 bytes
-rw-r--r--documentation/img/finalUI.jpgbin0 -> 127617 bytes
-rw-r--r--documentation/img/pluginEclipseMarketPlace2.jpgbin0 -> 374514 bytes
-rw-r--r--documentation/img/projectWizard2.jpgbin0 -> 137554 bytes
-rw-r--r--documentation/img/projectWizard3.jpgbin0 -> 116524 bytes
-rw-r--r--documentation/img/projectWizardAddArchetype.jpgbin0 -> 120648 bytes
-rw-r--r--documentation/original-drawings/createMavenProject.pngbin0 -> 665873 bytes
-rw-r--r--documentation/original-drawings/debugAddBreakPoint.pngbin0 -> 815134 bytes
-rw-r--r--documentation/original-drawings/debugAsMavenBuild.pngbin0 -> 835475 bytes
-rw-r--r--documentation/original-drawings/debugAsMavenBuild2.pngbin0 -> 577093 bytes
-rw-r--r--documentation/original-drawings/debugAsMavenBuild2.psdbin0 -> 3360579 bytes
-rw-r--r--documentation/original-drawings/debugAsMavenBuild3.pngbin0 -> 532518 bytes
-rw-r--r--documentation/original-drawings/debugAsMavenBuildAddSources.pngbin0 -> 737443 bytes
-rw-r--r--documentation/original-drawings/debugAsMavenBuildAddSources.psdbin0 -> 4162553 bytes
-rw-r--r--documentation/original-drawings/debugConfiguration.pngbin0 -> 288743 bytes
-rw-r--r--documentation/original-drawings/debugInBreakPoint.pngbin0 -> 768689 bytes
-rw-r--r--documentation/original-drawings/debugInBreakPointVariable.pngbin0 -> 693946 bytes
-rw-r--r--documentation/original-drawings/eclipse-without-designer-license-dialog.pngbin0 -> 144275 bytes
-rw-r--r--documentation/original-drawings/eclipseWithoutJdkError.pngbin0 -> 131134 bytes
-rw-r--r--documentation/original-drawings/eclipseWithoutJdkError.psdbin0 -> 1333998 bytes
-rw-r--r--documentation/original-drawings/finalUI.pngbin0 -> 287671 bytes
-rw-r--r--documentation/original-drawings/pluginConfirmInstall.pngbin0 -> 843365 bytes
-rw-r--r--documentation/original-drawings/pluginCreateDesign.pngbin0 -> 712533 bytes
-rw-r--r--documentation/original-drawings/pluginEclipseMarketPlace.pngbin0 -> 1108007 bytes
-rw-r--r--documentation/original-drawings/pluginEclipseMarketPlace2.pngbin0 -> 1041200 bytes
-rw-r--r--documentation/original-drawings/pluginEclipseMarketPlace2.psdbin0 -> 4898348 bytes
-rw-r--r--documentation/original-drawings/projectWizard1.pngbin0 -> 411157 bytes
-rw-r--r--documentation/original-drawings/projectWizard2.pngbin0 -> 478796 bytes
-rw-r--r--documentation/original-drawings/projectWizard2.psdbin0 -> 2954108 bytes
-rw-r--r--documentation/original-drawings/projectWizard3.pngbin0 -> 442080 bytes
-rw-r--r--documentation/original-drawings/projectWizard3.psdbin0 -> 2744999 bytes
-rw-r--r--documentation/original-drawings/projectWizardAddArchetype.pngbin0 -> 507031 bytes
-rw-r--r--documentation/tutorial.adoc884
38 files changed, 884 insertions, 0 deletions
diff --git a/documentation/img/createMavenProject.jpg b/documentation/img/createMavenProject.jpg
new file mode 100644
index 0000000000..45255e1acb
--- /dev/null
+++ b/documentation/img/createMavenProject.jpg
Binary files differ
diff --git a/documentation/img/debugAsMavenBuild.jpg b/documentation/img/debugAsMavenBuild.jpg
new file mode 100644
index 0000000000..f2e5c8db5b
--- /dev/null
+++ b/documentation/img/debugAsMavenBuild.jpg
Binary files differ
diff --git a/documentation/img/debugAsMavenBuild2.jpg b/documentation/img/debugAsMavenBuild2.jpg
new file mode 100644
index 0000000000..c1202aaaa0
--- /dev/null
+++ b/documentation/img/debugAsMavenBuild2.jpg
Binary files differ
diff --git a/documentation/img/debugAsMavenBuildAddSources.jpg b/documentation/img/debugAsMavenBuildAddSources.jpg
new file mode 100644
index 0000000000..b9e3275fdd
--- /dev/null
+++ b/documentation/img/debugAsMavenBuildAddSources.jpg
Binary files differ
diff --git a/documentation/img/debugInBreakPointVariable.jpg b/documentation/img/debugInBreakPointVariable.jpg
new file mode 100644
index 0000000000..0b4fc95e59
--- /dev/null
+++ b/documentation/img/debugInBreakPointVariable.jpg
Binary files differ
diff --git a/documentation/img/eclipseWithoutJdkError.jpg b/documentation/img/eclipseWithoutJdkError.jpg
new file mode 100644
index 0000000000..03f2e20fd4
--- /dev/null
+++ b/documentation/img/eclipseWithoutJdkError.jpg
Binary files differ
diff --git a/documentation/img/finalUI.jpg b/documentation/img/finalUI.jpg
new file mode 100644
index 0000000000..afb74be602
--- /dev/null
+++ b/documentation/img/finalUI.jpg
Binary files differ
diff --git a/documentation/img/pluginEclipseMarketPlace2.jpg b/documentation/img/pluginEclipseMarketPlace2.jpg
new file mode 100644
index 0000000000..e14b111a51
--- /dev/null
+++ b/documentation/img/pluginEclipseMarketPlace2.jpg
Binary files differ
diff --git a/documentation/img/projectWizard2.jpg b/documentation/img/projectWizard2.jpg
new file mode 100644
index 0000000000..5d639d11d9
--- /dev/null
+++ b/documentation/img/projectWizard2.jpg
Binary files differ
diff --git a/documentation/img/projectWizard3.jpg b/documentation/img/projectWizard3.jpg
new file mode 100644
index 0000000000..30fad8edf5
--- /dev/null
+++ b/documentation/img/projectWizard3.jpg
Binary files differ
diff --git a/documentation/img/projectWizardAddArchetype.jpg b/documentation/img/projectWizardAddArchetype.jpg
new file mode 100644
index 0000000000..c7fbd522b0
--- /dev/null
+++ b/documentation/img/projectWizardAddArchetype.jpg
Binary files differ
diff --git a/documentation/original-drawings/createMavenProject.png b/documentation/original-drawings/createMavenProject.png
new file mode 100644
index 0000000000..897a9d5076
--- /dev/null
+++ b/documentation/original-drawings/createMavenProject.png
Binary files differ
diff --git a/documentation/original-drawings/debugAddBreakPoint.png b/documentation/original-drawings/debugAddBreakPoint.png
new file mode 100644
index 0000000000..1dbf8bff68
--- /dev/null
+++ b/documentation/original-drawings/debugAddBreakPoint.png
Binary files differ
diff --git a/documentation/original-drawings/debugAsMavenBuild.png b/documentation/original-drawings/debugAsMavenBuild.png
new file mode 100644
index 0000000000..30c3028a09
--- /dev/null
+++ b/documentation/original-drawings/debugAsMavenBuild.png
Binary files differ
diff --git a/documentation/original-drawings/debugAsMavenBuild2.png b/documentation/original-drawings/debugAsMavenBuild2.png
new file mode 100644
index 0000000000..3062fe64c9
--- /dev/null
+++ b/documentation/original-drawings/debugAsMavenBuild2.png
Binary files differ
diff --git a/documentation/original-drawings/debugAsMavenBuild2.psd b/documentation/original-drawings/debugAsMavenBuild2.psd
new file mode 100644
index 0000000000..a3b7880b29
--- /dev/null
+++ b/documentation/original-drawings/debugAsMavenBuild2.psd
Binary files differ
diff --git a/documentation/original-drawings/debugAsMavenBuild3.png b/documentation/original-drawings/debugAsMavenBuild3.png
new file mode 100644
index 0000000000..62e4825e5c
--- /dev/null
+++ b/documentation/original-drawings/debugAsMavenBuild3.png
Binary files differ
diff --git a/documentation/original-drawings/debugAsMavenBuildAddSources.png b/documentation/original-drawings/debugAsMavenBuildAddSources.png
new file mode 100644
index 0000000000..458d6807c1
--- /dev/null
+++ b/documentation/original-drawings/debugAsMavenBuildAddSources.png
Binary files differ
diff --git a/documentation/original-drawings/debugAsMavenBuildAddSources.psd b/documentation/original-drawings/debugAsMavenBuildAddSources.psd
new file mode 100644
index 0000000000..9b4b75db5e
--- /dev/null
+++ b/documentation/original-drawings/debugAsMavenBuildAddSources.psd
Binary files differ
diff --git a/documentation/original-drawings/debugConfiguration.png b/documentation/original-drawings/debugConfiguration.png
new file mode 100644
index 0000000000..28c786a99a
--- /dev/null
+++ b/documentation/original-drawings/debugConfiguration.png
Binary files differ
diff --git a/documentation/original-drawings/debugInBreakPoint.png b/documentation/original-drawings/debugInBreakPoint.png
new file mode 100644
index 0000000000..6e88161980
--- /dev/null
+++ b/documentation/original-drawings/debugInBreakPoint.png
Binary files differ
diff --git a/documentation/original-drawings/debugInBreakPointVariable.png b/documentation/original-drawings/debugInBreakPointVariable.png
new file mode 100644
index 0000000000..2a86fb42cc
--- /dev/null
+++ b/documentation/original-drawings/debugInBreakPointVariable.png
Binary files differ
diff --git a/documentation/original-drawings/eclipse-without-designer-license-dialog.png b/documentation/original-drawings/eclipse-without-designer-license-dialog.png
new file mode 100644
index 0000000000..10d5c4f0f3
--- /dev/null
+++ b/documentation/original-drawings/eclipse-without-designer-license-dialog.png
Binary files differ
diff --git a/documentation/original-drawings/eclipseWithoutJdkError.png b/documentation/original-drawings/eclipseWithoutJdkError.png
new file mode 100644
index 0000000000..13d882c5dc
--- /dev/null
+++ b/documentation/original-drawings/eclipseWithoutJdkError.png
Binary files differ
diff --git a/documentation/original-drawings/eclipseWithoutJdkError.psd b/documentation/original-drawings/eclipseWithoutJdkError.psd
new file mode 100644
index 0000000000..15d26605bc
--- /dev/null
+++ b/documentation/original-drawings/eclipseWithoutJdkError.psd
Binary files differ
diff --git a/documentation/original-drawings/finalUI.png b/documentation/original-drawings/finalUI.png
new file mode 100644
index 0000000000..00824a84d0
--- /dev/null
+++ b/documentation/original-drawings/finalUI.png
Binary files differ
diff --git a/documentation/original-drawings/pluginConfirmInstall.png b/documentation/original-drawings/pluginConfirmInstall.png
new file mode 100644
index 0000000000..5f48f37f48
--- /dev/null
+++ b/documentation/original-drawings/pluginConfirmInstall.png
Binary files differ
diff --git a/documentation/original-drawings/pluginCreateDesign.png b/documentation/original-drawings/pluginCreateDesign.png
new file mode 100644
index 0000000000..bfc646f1e4
--- /dev/null
+++ b/documentation/original-drawings/pluginCreateDesign.png
Binary files differ
diff --git a/documentation/original-drawings/pluginEclipseMarketPlace.png b/documentation/original-drawings/pluginEclipseMarketPlace.png
new file mode 100644
index 0000000000..44eb33ccae
--- /dev/null
+++ b/documentation/original-drawings/pluginEclipseMarketPlace.png
Binary files differ
diff --git a/documentation/original-drawings/pluginEclipseMarketPlace2.png b/documentation/original-drawings/pluginEclipseMarketPlace2.png
new file mode 100644
index 0000000000..82786b86ee
--- /dev/null
+++ b/documentation/original-drawings/pluginEclipseMarketPlace2.png
Binary files differ
diff --git a/documentation/original-drawings/pluginEclipseMarketPlace2.psd b/documentation/original-drawings/pluginEclipseMarketPlace2.psd
new file mode 100644
index 0000000000..b65e9c55c8
--- /dev/null
+++ b/documentation/original-drawings/pluginEclipseMarketPlace2.psd
Binary files differ
diff --git a/documentation/original-drawings/projectWizard1.png b/documentation/original-drawings/projectWizard1.png
new file mode 100644
index 0000000000..d37b2ba79b
--- /dev/null
+++ b/documentation/original-drawings/projectWizard1.png
Binary files differ
diff --git a/documentation/original-drawings/projectWizard2.png b/documentation/original-drawings/projectWizard2.png
new file mode 100644
index 0000000000..e81fb698fc
--- /dev/null
+++ b/documentation/original-drawings/projectWizard2.png
Binary files differ
diff --git a/documentation/original-drawings/projectWizard2.psd b/documentation/original-drawings/projectWizard2.psd
new file mode 100644
index 0000000000..91e859fd2c
--- /dev/null
+++ b/documentation/original-drawings/projectWizard2.psd
Binary files differ
diff --git a/documentation/original-drawings/projectWizard3.png b/documentation/original-drawings/projectWizard3.png
new file mode 100644
index 0000000000..60eafcb710
--- /dev/null
+++ b/documentation/original-drawings/projectWizard3.png
Binary files differ
diff --git a/documentation/original-drawings/projectWizard3.psd b/documentation/original-drawings/projectWizard3.psd
new file mode 100644
index 0000000000..a9f90aaac2
--- /dev/null
+++ b/documentation/original-drawings/projectWizard3.psd
Binary files differ
diff --git a/documentation/original-drawings/projectWizardAddArchetype.png b/documentation/original-drawings/projectWizardAddArchetype.png
new file mode 100644
index 0000000000..7ffadf45bd
--- /dev/null
+++ b/documentation/original-drawings/projectWizardAddArchetype.png
Binary files differ
diff --git a/documentation/tutorial.adoc b/documentation/tutorial.adoc
new file mode 100644
index 0000000000..db65033065
--- /dev/null
+++ b/documentation/tutorial.adoc
@@ -0,0 +1,884 @@
+:experimental:
+:sectnums:
+:imagesdir: img
+
+= Vaadin tutorial
+
+This tutorial gives you an overview of how you can use
+https://vaadin.com/framework[Vaadin Framework] to build single-page web UI's for your Java
+application. All you need to start with it is JDK 8 and an https://en.wikipedia.org/wiki/Integrated_development_environment[IDE] like Eclipse.
+No extensive knowledge of Java is even needed to get started, only the basic programming skills are required. Although the tutorial is built for
+Eclipse users, you can use your IDE of choice.
+
+We'll build a simple customer management system. It is not a real app, but we'll
+use an in-memory "backend" so that you can understand how to hook it to an
+existing Java based backend. We'll cover the basic Vaadin development and you
+can use the result as a basis for more experiments with Vaadin, like using
+add-ons, your own custom look and feel (aka. theme), adding new views or optimizing the result for
+mobile support.
+
+You'll need about 20 - 60 minutes to complete the tutorial, depending on your
+existing experience, but naturally you can just do the beginning of
+the exercise or pick any of the steps you want. To start from a specific step,
+we have prepared the example code after each step to be
+downloaded as a zip file. If don't want to do the exercise at all, you can also
+just https://github.com/vaadin/tutorial/[downlood the final application] and
+play around with it.
+
+The tutorial uses Java 8, so ensure you have an up-to-date JDK 8 installed. Most
+linux distributions can use package managers to install JDK8, Windows and Mac users should
+download it from
+http://www.oracle.com/technetwork/java/javase/downloads/index.html[Oracle's Java
+SE site].
+
+Also make sure you have the latest version of your IDE. Eclipse is available in
+various packages, be sure to download the *Eclipse IDE for Java EE Developers*
+from http://www.eclipse.org/downloads/[eclipse.org].
+
+== Creating a project using an archetype
+
+As a starting point for the application, we'll use a Maven archetype called
+vaadin-archetype-application. Maven archetypes are project stubs with basic
+build script and some example code.
+
+Start by choosing menu:File[New > Maven Project] from the menu.
+
+image::createMavenProject.jpg[Create a new Maven built Vaadin project.]
+
+TIP: If the "Maven Project" is not visible in the menu, you should switch to the
+_Java EE_ perspective. Use the shortcut button in the toolbar or
+menu:Window[Perspective] to do this.
+
+The first page in the wizard is ok with its defaults, but on the second page
+you'll need to choose _vaadin-archetype-application_ archetype. You can first
+try to find it using the filtering function, but in some cases Eclipse hasn't
+yet indexed the archetype catalog, so you might need to manually add the
+archetype details with the _Add Archetype_ button. The Group Id is _com.vaadin_,
+the Artifact Id is _vaadin-archetype-application_ and as a version you can use
+the latest Vaadin version, at the time of writing _7.6.2_. The _Repository URL_
+can be left blank.
+
+CAUTION: Eclipse has a bug in its project wizard. If
+_vaadin-archetype-application_ doesn't appear in the listing, even though you
+added it using the _Add Archetype_ button, close the whole new project wizard
+and re-open it by selecting menu:File[New > Maven Project] again. The archetype
+then typically appears in the listing and can be found by the filtering
+functionality.
+
+On the next wizard page, type in _my.vaadin_ as the Group Id, _app_ as the
+Artifact Id and click _Finish_. If this is your first Vaadin app, creating
+a project might take a while, depending on the speed of your network, as Vaadin
+libraries and other dependencies are being downloaded. Maven caches these on
+your local file system and creating your next Maven based Vaadin project will be much
+faster.
+
+Right click on the newly created project and choose menu:Run as[Maven Install].
+This will initiate a full build of your application and will finally create a
+https://en.wikipedia.org/wiki/WAR_(file_format)[war] file to the "target" directory that you can deploy to your application
+server. As Maven might again need to download some new modules and the project
+has a setup for add-on usage and contains a project specific theme, the first
+build will take a while.
+
+TIP: For the Maven compilation to work you need a JDK to be configured in your
+Eclipse in menu:Window[Preferences > Java > Installed JREs > Add...]. This step
+is necessary at least on Windows, if you are using a fresh installation of
+Eclipse or for some other reason haven't configured a JDK to your Eclipse. The
+JDK by default installs to _\Program Files\Java_ on Windows. You
+can make JDK the default JRE for your Eclipse.
+
+While the build is running, let's have a look at what the archetype created for
+you. You can browse your project resources from the tree structure in the
+_Project Explorer_. Maven's _pom.xml_ on top level contains settings for your
+projects build and declares the used dependencies. Open _Java Resources_ and
+below it _src/main/java_, the main source directory, and _my.vaadin.app_, the
+main Java package that will contain your Vaadin UI code.
+
+TIP: Eclipse shows all project files in the Project Explorer. In this case you
+can also find your _.java_ files via top level _src_ node, but the suggested
+method is to access them via the _Java Resources_ node, which is optimized for
+editing Java source code.
+
+The UI code (and the Servlet declaration) used by the application stub can be
+found in the _MyUI.java_ file. Let's read it through to see how it works. The
+_init_ method of a UI class is triggered when a user enters your web
+application. The VerticalLayout is one of the most used layout objects, which
+are used to position and display other Vaadin components in your UI classes. The
+example code creates one TextField to allow the user to input her name and a
+Button whose click listener dynamically adds a new Label component to the main
+layout. In the end of the init method we just configure the main layout and
+place components into it and set it to be the content of MyUI.
+
+To test your first Vaadin application, right click on the project and choose
+menu:Debug as[Maven build...]. The debug mode is slightly slower than the basic run
+mode, but it often helps you to figure out what is happening in your
+application.
+
+image::debugAsMavenBuild.jpg[Starting the server using a Maven target]
+
+In the dialog, type _Run in jetty_ to the _Name_ input and _jetty:run_ to the
+_Goals_ input.
+
+image::debugAsMavenBuild2.jpg[Generating a Maven launch for jetty:run target]
+
+Before clicking debug, to make sure debugging works properly, add your Java
+project to the source lookup path from the _Source_ tab, like it is being done
+in the image below.
+
+image::debugAsMavenBuildAddSources.jpg[Adding sources for debugging]
+
+Now click _Debug_ to continue. This will download a small Java web server
+(if not cached to your local Maven repository), and use it to host
+your application. Once the server has started, point your browser to the URL
+http://localhost:8080/[http://localhost:8080/] to see the running application.
+
+If you make changes to the code, the jetty server will notice the changes and in
+a couple of seconds most changes are automatically deployed. Reloading the page
+in your browser will show the changes.
+
+TIP: In some cases your JVM might not allow injecting changes on the fly. In
+these cases, Eclipse will complain about "Hot code replacement error". Just
+choose to restart the server to get the latest changes. Many Java developers use
+a commercial tool called http://zeroturnaround.com/software/jrebel/[JRebel] to make code
+replacement work better.
+
+Mastering the usage of the java debugger is also handy to better understand how your
+application actually works and fixing bugs that all developers write at some
+point. As Vaadin is "only" Java code, you can use all of Java's debugging tools, which cannot be done with other UI frameworks where the UI is written (partly) in HTML and/or JavaScript. Double click on the line number in the Java editor, for example of the
+following line in the click listener:
+
+[source,java]
+----
+ layout.addComponent(new Label("Thanks " + name.getValue()
+----
+
+This will add a breakpoint to the selected line. If you then click the button in
+your browser, the execution of the application will stop on that line. Eclipse
+will ask you to enter to _Debugging perspective_ and you can inspect its
+variables and step through the execution. Clicking on the _play_ icon in the
+toolbar will continue the execution. Double click the same line again to remove
+the breakpoint.
+
+image::debugInBreakPointVariable.jpg[Execution in a break point in the button click listener]
+
+Clicking the red square in the Console view will terminate the server process.
+You can restart it easily form the run/debug history. You can find that from the
+small down arrow next to the green play button or bug button (for the debug
+mode) in the toolbar. Alternatively you can use the main menu menu:Run[Run
+history/Debug history > Run in Jetty].
+
+To get back to the _Java EE Perspective_, an Eclipse mode designed for editing
+Java web app code, click the _Java EE_ button in the toolbar.
+
+== Adding a demo "backend"
+
+Before getting more into real Vaadin development, let's introduce some domain
+objects and a "fake backend". In a real world application, you'll most likely
+have something similar, implemented with, for example, JPA and EJB or a Spring based
+service.
+
+Copy the following three classes from github to your project. Class names
+point to the classes hosted in Github. Copying classes can be done in many ways.
+
+TIP: The fastest way to copy classes using Eclipse is to use your good old
+clipboard. Select the text content of the whole class from your browser, choose
+menu:Edit[Copy], focus the node representing the _my.vaadin.app_ Java package in
+Eclipse's Java Resources view and choose menu:Edit[Paste]. Eclipse is smart
+enough to automatically create a properly named Java file for the class.
+
+ * https://raw.githubusercontent.com/vaadin/tutorial/master/src/main/java/my/vaadin/app/CustomerStatus.java[CustomerStatus] - this is a simple enum class
+ * https://raw.githubusercontent.com/vaadin/tutorial/master/src/main/java/my/vaadin/app/Customer.java[Customer] - this is the main domain object, a basic Java bean that we'll be
+ using in our example
+ * https://raw.githubusercontent.com/vaadin/tutorial/master/src/main/java/my/vaadin/app/CustomerService.java[CustomerService] - this is a simple facade via which you can request and modify Customer instances. You can think of this as your entry point to your fake database.
+
+In the next steps, we'll be using these classes and build a UI around them. The
+actual implementation of these classes is not relevant for this tutorial, but
+feel free to have a look around.
+
+== Listing entities in a Grid
+
+TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step2.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
+
+Often when you start building a UI for a data centric application, the first
+thing you want to do is to list your data from your backend. There are several
+components and methods in Vaadin to do this. In this example, we'll use the Grid
+component for tabular presentation of our customers.
+
+We'll start by introducing a Grid field to the MyUI class. We could of course
+just introduce the Grid as a variable in the init method, but we'll most likely
+want to refer to it later. Also, let's get a reference to the CustomerService.
+
+[source,java]
+----
+public class MyUI extends UI {
+
+ // Add next two lines:
+ private CustomerService service = CustomerService.getInstance();
+ private Grid grid = new Grid();
+
+ // the rest is already there...
+ @Override
+ protected void init(VaadinRequest vaadinRequest) {
+----
+
+TIP: If you are new to Java development, you probably don't feel comfortable
+with the red compilation error for the line where the Grid got introduced, due
+to a missing import. This is easily fixed in Eclipse by using the
+menu:Source[Organize Imports] command. Learn its shortcut (kbd:[Ctrl-Shift-O] or
+kbd:[CMD-Shift-O] on Macs), you'll be using it a lot in Java development. In
+possible class name collisions, always choose the appropriate class from the
+_com.vaadin.ui_ package if you want to import core Vaadin UI classes like the
+Grid.
+
+To simply list all properties of all Customer objects from the backend service,
+replace the init method with the following snippet:
+
+[source,java]
+----
+@Override
+protected void init(VaadinRequest vaadinRequest) {
+ final VerticalLayout layout = new VerticalLayout();
+
+ // add Grid to the layout
+ layout.addComponents(grid);
+
+ // fetch list of Customers from service and assign it to Grid
+ List<Customer> customers = service.findAll();
+ grid.setContainerDataSource(new BeanItemContainer<>(Customer.class, customers));
+
+ layout.setMargin(true);
+ setContent(layout);
+}
+----
+
+TIP: Again, use the organize imports feature. The List object we use here is
+_java.util.List_.
+
+As we'll want to refresh the listing from various places in our application,
+extract the customer listing part into its own "updateList" method with the
+*public* modifier. The public modifier is handy later when we want to update the
+listing from other classes. You can let Eclipse help here by selecting the
+relevant lines and using the "quick fix" feature (kbd:[Ctrl+1] or kbd:[Cmd+1] on
+Macs). The extracted method call looks like this:
+
+[source,java]
+----
+ public void updateList() {
+ List<Customer> customers = service.findAll();
+ grid.setContainerDataSource(new BeanItemContainer<>(Customer.class, customers));
+ }
+----
+
+If you try the application now, you'll see that quite many properties of the
+customers are shown in the grid. To limit the visible properties, configure
+the Grid using the _setColumns_ method to only show "firstName", "lastName" and
+"email" properties.
+
+[source,java]
+----
+ grid.setColumns("firstName", "lastName", "email");
+----
+
+At this point the body of the MyUI class should look like this (servlet declaration
+omitted):
+
+[source,java]
+----
+private CustomerService service = CustomerService.getInstance();
+private Grid grid = new Grid();
+
+@Override
+protected void init(VaadinRequest vaadinRequest) {
+ final VerticalLayout layout = new VerticalLayout();
+
+ grid.setColumns("firstName", "lastName", "email");
+ // add Grid to the layout
+ layout.addComponent(grid);
+
+ updateList();
+
+ layout.setMargin(true);
+ setContent(layout);
+}
+
+public void updateList() {
+ // fetch list of Customers from service and assign it to Grid
+ List<Customer> customers = service.findAll();
+ grid.setContainerDataSource(new BeanItemContainer<>(Customer.class, customers));
+}
+----
+
+You can now save your changes to the file and verify the changes from your browser.
+You can do this at any point during the rest of the tutorial as well.
+
+== Creating live filtering for entities
+
+TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step3.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
+
+A search functionality is expected in every modern application and it is
+also a nice Vaadin development exercise. Let's add a filtering functionality to
+the Customer listing we created in the previous step.
+
+We'll start by introducing a TextField component as a field to our UI class:
+
+[source,java]
+----
+ private TextField filterText = new TextField();
+----
+
+In the _init_ method, configure the text field to contain a helpful input prompt
+and add a text change listener to the field. The exact place of these lines is
+not important, but add them, for example, after you have introduced the _layout_
+object.
+
+[source,java]
+----
+filterText.setInputPrompt("filter by name...");
+filterText.addTextChangeListener(e -> {
+ grid.setContainerDataSource(new BeanItemContainer<>(Customer.class,
+ service.findAll(e.getText())));
+});
+----
+
+TIP: To keep your code more readable, you can use autoformat after you write or
+copy paste code snippets. The default keyboard shortcut in Eclipse is
+kbd:[Ctrl+Shift+F] or kbd:[Cmd+Shift+F]
+
+The text change listener is another listener (in addition to the more commonly
+used ValueChangeListener) you can use with text fields in Vaadin. It is fired
+lazily while the user is typing, but only when there is a small pause in the
+typing. This makes it perfect for this kind of automatic filtering. When the
+user has changed the text, we'll just update the listing like in the updateList
+method, but use the current text as a filter for entries.
+
+To keep the _updateList_ method functional, it should also take into
+consideration the possible value in the filterText field. Change the line for
+fetching the customers into this:
+
+[source,java]
+----
+ List<Customer> customers = service.findAll(filterText.getValue());
+----
+
+Before adding the text field to the UI, let's improve the usability a bit
+and make a short exercise to compose better components from lower level UI
+components. The search field can naturally be cleared with the keyboard, but let's
+add a clear button next to the text field. Start by adding the following lines
+to the init method, for example right after your filterText configuration:
+
+[source,java]
+----
+Button clearFilterTextBtn = new Button(FontAwesome.TIMES);
+clearFilterTextBtn.setDescription("Clear the current filter");
+clearFilterTextBtn.addClickListener(e -> {
+ filterText.clear();
+ updateList();
+});
+----
+
+Vaadin contains a set of built in icons, from which we use the "X" icon,
+_FontAwesome.TIMES_, here, which most users will recognise as a functionality to clear
+the value. If we set the description to a component, it will be shown as a
+tooltip for those users who hover the cursor over the button and wonder what to
+do with it. In the click listener, we simply clear the text from the field and
+refresh the content of the listing.
+
+Vaadin contains lots of different kinds of layouts. The simplest way to align
+the text field and the button next to each other would be to use a
+HorizontalLayout. An alternative way we use here is using a CssLayout, which is
+a lightweight layout that is easy to customize with css. Even if you wouldn't
+want to play with CSS yourself, you can often use one of the existing style
+rules in the default _Valo_ theme. The following snippet will create a nice
+compact "composition" of both the TextField and the clear button. Add these
+lines to the init method right after you configured the _clearFilterTextBtn_:
+
+[source,java]
+----
+CssLayout filtering = new CssLayout();
+filtering.addComponents(filterText, clearFilterTextBtn);
+filtering.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
+----
+
+Finally, *change* the row in the init method that currently adds only the grid,
+to add both _filtering_ composition and the _grid_ to the main _layout_ of the
+application.
+
+[source,java]
+----
+ layout.addComponents(filtering, grid);
+----
+
+Now it is a good place to save your changes and try them in your browser.
+
+== Creating a form to edit Customer objects
+
+To edit and add Customer objects we need to create a form, that edits the
+values in our domain objects. This tutorial has two alternative methods to do
+that. Pick either of them.
+
+=== Creating a form using Vaadin Designer
+
+TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step4.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
+
+The form to edit Customer objects can be built using several methods of which
+the visual composition by drag 'n' drop is the most intuitive. Vaadin
+Designer is an Eclipse plugin that you can install and do WYSIWYG editing of
+your view code. We'll use it to create the form and then hook the editing logic
+to it with Java.
+
+TIP: If you are using another IDE or just prefer to compose your user interface
+with code, take the alternative step, <<Creating a form using plain Java>>,
+where the CustomerForm is composed using plain Java code.
+
+==== Installing Vaadin Designer
+
+Vaadin Designer comes as an integrated part of Vaadin Plugin for Eclipse. It can
+be installed easily via Eclipse Marketplace. Choose menu:Help[Eclipse Marketplace]
+
+In the dialog, just search for Vaadin and click _install_ to mark it for
+installation. Clicking _Install Now_ will take you to choose the modules you want
+and accept the license agreement.
+
+image::pluginEclipseMarketPlace2.jpg[Selecting Vaadin Plugin for Eclipse for installation in Eclipse Marketplace]
+
+If you get a security warning about the software containing unsigned content,
+just accept the warning by clicking OK. After installation, Eclipse asks if you
+want to restart. Click Yes.
+
+TIP: When you use Vaadin Designer for the first time in the next
+step, it will ask for a license key. Get a key from
+https://vaadin.com/designer. If you are not willing to buy a license now, just
+acquire a trial license.
+
+==== Creating the form design
+
+The following screencast will show you how to produce the
+_CustomerFormDesign.html_, a design file we need in this tutorial. Use pause and
+slow motion to follow better what is being done in the video. Feel free to get creative!
+
+video::B5dN69NSS78[youtube, width="640", height="400"]
+
+TIP: At any point of the process, you can also switch to the markup mode where
+you can edit the raw content of the .html file. If you wish to take a shortcut
+or think you did something wrong when using the designer, you can just
+copy-paste the content of https://github.com/vaadin/tutorial/blob/master/src/main/resources/my/vaadin/app/CustomerFormDesign.html[the final state] to your own .html file.
+
+At this point we only have a static mockup of the actual UI. To implement a
+functional form component, we need some Java code as well. Vaadin Designer
+automatically creates a similarly named Java class, but a good habit is to never touch the auto-generated file, in this case the
+CustomerFormDesign.java file. If you'd introduce a new field to your form,
+your changes to CustomerFormDesign would be overridden by the tooling. Instead,
+we'll create a class called CustomerForm which inherits from the auto-generated
+CustomerFormDesign class.
+
+Start by creating a new Java class with the name CustomerForm. In Eclipse, right
+click on the "my.vaadin.app" package and choose menu:New[Class]. Type in the
+name _CustomerForm_, define the superclass as
+_my.vaadin.app.CustomerFormDesign_ and click _finish_.
+
+From the superclass, we inherit all the UI elements that we named when using
+the designer. E.g. by simply referencing to "save" field in the CustomerForm,
+we'll have access to the save button we previously created.
+
+We will later need a reference to the currently edited Customer object,
+CustomerService and the MyUI that uses this class. Add these fields and a
+basic constructor that accepts MyUI as a parameter to the CustomerForm class:
+
+[source,java]
+----
+CustomerService service = CustomerService.getInstance();
+private Customer customer;
+private MyUI myUI;
+
+public CustomerForm(MyUI myUI) {
+ this.myUI = myUI;
+}
+----
+
+Although the form is not yet fully functional, you might want to see what it
+looks like at this point. Add it as a field to the _MyUI_ class:
+
+[source,java]
+----
+ CustomerForm form = new CustomerForm(this);
+----
+
+Now let's modify the init method in MyUI to show the form. Let's wrap both the
+Grid and the CustomerForm in a horizontal layout and configure the Grid to use
+all of the available space more efficiently. Replace the line
+*layout.addComponents(filtering, grid);* with the following:
+
+[source,java]
+----
+HorizontalLayout main = new HorizontalLayout(grid, form);
+main.setSpacing(true);
+main.setSizeFull();
+grid.setSizeFull();
+main.setExpandRatio(grid, 1);
+
+layout.addComponents(filtering, main);
+----
+
+If you now save your changes and reload your application page in a browser,
+you should see your CustomerForm next to the grid that lists your
+existing entities.
+
+Let's get back to the CustomerForm. The first thing we'll need is to populate
+the options for the select. To add all enum values as valid selections, add the
+following line to the constructor:
+
+[source,java]
+----
+ status.addItems(CustomerStatus.values());
+----
+
+Let's also improve the UX a bit. When building the design, we already
+emphasized the save button with a ValoTheme.BUTTON_PRIMARY style name. Thus, it
+would be natural if the enter-key would do the same action as clicking the
+save button. Assign a keyboard shortcut to the save button with this line in the
+constructor:
+
+[source,java]
+----
+save.setClickShortcut(KeyCode.ENTER);
+----
+
+To finish our form, we need to create a public API that we will use in the next
+part from MyUI, to pass in a Customer object that the form should edit. We
+will also add some logic to actually save the changes. We'll start by creating a
+setter method to the Customer field. Just type _setCus_ in the body of the
+class and hit autocomplete (kbd:[Ctrl+Space]) and Eclipse will create a method
+stub for you. Complete it with the following implementation:
+
+[source,java]
+----
+public void setCustomer(Customer customer) {
+ this.customer = customer;
+ BeanFieldGroup.bindFieldsUnbuffered(customer, this);
+
+ // Show delete button for only customers already in the database
+ delete.setVisible(customer.isPersisted());
+ setVisible(true);
+ firstName.selectAll();
+}
+----
+
+In addition to saving the reference of the currently edited Customer object, we are
+calling the _BeanFieldGroup.bindFieldsUnbuffered_ method. It will initialize all
+similarly named editor fields in this form with the values from their
+counterpart in the given Customer object. Also, it will automatically update the
+values in the domain objects as the corresponding field value changes in the
+user interface.
+
+TIP: If the naming convention based databinding doesn't fit your needs, you
+can use
+https://www.vaadin.com/api/com/vaadin/data/fieldgroup/PropertyId.html[PropertyId]
+annotation on fields to explicitly declare the edited property.
+
+We'll also want to ensure the form is visible and that focus goes to the
+firstName field to improve user experience. As we will be using the form to
+edit both new non-persisted objects and existing customers, we will also show
+the delete button only for customers that are already persisted in the backend.
+
+The last thing we need to do is to handle save and delete button clicks. Add
+the following methods to the CustomerForm class:
+
+[source,java]
+----
+private void delete() {
+ service.delete(customer);
+ myUI.updateList();
+ setVisible(false);
+}
+
+private void save() {
+ service.save(customer);
+ myUI.updateList();
+ setVisible(false);
+}
+----
+
+Finally, we'll add listeners to the buttons to call these methods. Adding these
+simple lambda expressions to the constructor will take care of that:
+
+[source,java]
+----
+save.addClickListener(e->this.save());
+delete.addClickListener(e->this.delete());
+----
+
+TIP: For a truly re-usable form component in a real life project, you'd want to
+introduce an interface to replace the myUI field or, even better, use an event
+system like https://vaadin.com/wiki/-/wiki/main/Events+and+contexts[CDI events]
+to completely decouple the components. We'll leave that out of this tutorial for
+simplicity.
+
+=== Creating a form using plain Java
+
+This is an alternative step to the <<Creating a form using Vaadin Designer>>,
+where you'll build the form UI programmatically in plain Java. If you already
+completed the step using Vaadin Designer, you can proceed to
+<<Connecting the form to the application>>.
+
+Start by creating a new Java class with the name CustomerForm. In Eclipse right
+click on the "my.vaadin.app" package and choose menu:New[Class]. Type in the
+name _CustomerForm_, define the superclass as _com.vaadin.ui.FormLayout_ and
+click _finish_.
+
+In the form, we'll need editor fields for each property in our Customer domain
+class. There are different kinds of fields in Vaadin for editing different kinds
+of properties. In this example, we'll use a TextField, a PopupDateField and a
+NativeSelect. Add the following field declarations and action buttons as Java
+fields to the CustomerForm:
+
+[source,java]
+----
+private TextField firstName = new TextField("First name");
+private TextField lastName = new TextField("Last name");
+private TextField email = new TextField("Email");
+private NativeSelect status = new NativeSelect("Status");
+private PopupDateField birthdate = new PopupDateField("Birthday");
+private Button save = new Button("Save");
+private Button delete = new Button("Delete");
+----
+
+Also, we will laterneed a reference to the currently edited Customer object,
+CustomerService and the MyUI that uses this class. Add these fields and a
+basic constructor that accepts MyUI as a parameter to the CustomerForm class:
+
+[source,java]
+----
+private CustomerService service = CustomerService.getInstance();
+private Customer customer;
+private MyUI myUI;
+
+public CustomerForm(MyUI myUI) {
+ this.myUI = myUI;
+
+ setSizeUndefined();
+ HorizontalLayout buttons = new HorizontalLayout(save, delete);
+ buttons.setSpacing(true);
+ addComponents(firstName, lastName, email, status, birthdate, buttons);
+}
+----
+
+In the constructor we make the form size undefined, which practically means it
+will consume the minimum space defined by its content. Then we'll just add all
+the fields to the CustomerForm and add action buttons to the bottom - side-by-side
+using a HorizontalLayout. Although the form is not yet fully functional, you
+might want to see what it looks like at this point. Add it as a field to the MyUI
+class:
+
+[source,java]
+----
+ CustomerForm form = new CustomerForm(this);
+----
+
+Now let's modify the init method in MyUI to show the form. Let's wrap both the
+Grid and the CustomerForm in a horizontal layout and configure the Grid to use
+all of the available space more efficiently. Replace the line
+*layout.addComponents(filtering, grid);* with the following:
+
+[source,java]
+----
+HorizontalLayout main = new HorizontalLayout(grid, form);
+main.setSpacing(true);
+main.setSizeFull();
+grid.setSizeFull();
+main.setExpandRatio(grid, 1);
+
+layout.addComponents(filtering, main);
+----
+
+When you now save your changes and reload your application page in your browser,
+you should see your CustomerForm next to the grid that lists your
+existing entities.
+
+Let's get back to the CustomerForm. The first thing we'll need is to populate
+the options for the select. To add all enum values as valid selections, add the
+following line to the constructor:
+
+[source,java]
+----
+ status.addItems(CustomerStatus.values());
+----
+
+Let's also improve the UX a bit. The most common thing your users will want to
+do with this kind of form is to save it. Let's decorate the button with a style
+name that makes it more prominent in the UI and give it a keyboard shortcut -
+simply an enter hit in this case:
+
+[source,java]
+----
+save.setStyleName(ValoTheme.BUTTON_PRIMARY);
+save.setClickShortcut(KeyCode.ENTER);
+----
+
+To finish our form, we need to create a public API that we will use in the next
+part from the MyUI, to pass in a Customer object that the form should edit. We
+will also add some logic to actually save the changes. We'll start by creating a
+setter method for the Customer field. Just type _setCus_ in the body of the
+class and hit autocomplete (kbd:[Ctrl+Space]) and Eclipse will create a method
+stub for you. Complete it with the following implementation:
+
+[source,java]
+----
+public void setCustomer(Customer customer) {
+ this.customer = customer;
+ BeanFieldGroup.bindFieldsUnbuffered(customer, this);
+
+ // Show delete button for only customers already in the database
+ delete.setVisible(customer.isPersisted());
+ setVisible(true);
+ firstName.selectAll();
+}
+----
+
+In addition to saving the reference of the currently edited Customer object, we are
+calling _BeanFieldGroup.bindFieldsUnbuffered_ method. It will initialise all
+similarly named editor fields in this form with the values from their
+counterpart in the given Customer object. Also, it will automatically update the
+values in the domain objects as the corresponding field value changes in the
+user interface.
+
+TIP: If the naming convention based databinding doesn't fit your needs, you
+can use
+https://www.vaadin.com/api/com/vaadin/data/fieldgroup/PropertyId.html[PropertyId]
+annotation on fields to explicitly declare the edited property.
+
+We'll also want to ensure the form is visible and that the focus goes to the
+firstName field to improve the user experience. As we will be using the form to
+edit both new non-persisted objects and existing customers, we will also show
+the delete button only for customers that are already persisted in the backend.
+
+The last thing we need to do is to handle save and delete button clicks. Add
+the following methods to the CustomerForm class:
+
+[source,java]
+----
+private void delete() {
+ service.delete(customer);
+ myUI.updateList();
+ setVisible(false);
+}
+
+private void save() {
+ service.save(customer);
+ myUI.updateList();
+ setVisible(false);
+}
+----
+
+Finally, we'll add listeners to the buttons to call these methods. Adding these
+simple lambda expressions to the constructor will take care of that:
+
+[source,java]
+----
+save.addClickListener(e->this.save());
+delete.addClickListener(e->this.delete());
+----
+
+TIP: For a truly re-usable form component in a real life project, you'd want to
+introduce an interface to replace the myUI field or, event better, use an event
+system like https://vaadin.com/wiki/-/wiki/main/Events+and+contexts[CDI events]
+to completely decouple the components. We'll leave that out of this tutorial for
+simplicity.
+
+== Connecting the form to the application
+
+TIP: Starting from this step directly? https://github.com/vaadin/tutorial/archive/step5.zip[Download the project] for this step, extract the zip file and choose menu:Import...[Maven>Existing Maven project].
+
+In this part, we'll use the CustomerForm class, which we created in the
+previous step, from the MyUI class. We will use it for both editing the existing
+customers and creating new ones.
+
+In the previous part, we already added the form to the _MyUI_ to see what it looks
+like. By default, we want it to be invisible, so let's first hide it
+by adding this line to the _init_ method of MyUI class:
+
+[source,java]
+----
+form.setVisible(false);
+----
+
+To edit the customer chosen from the Grid, add the following selection listener to
+the end of the _init_ method:
+
+[source,java]
+----
+grid.addSelectionListener(event -> {
+ if (event.getSelected().isEmpty()) {
+ form.setVisible(false);
+ } else {
+ Customer customer = (Customer) event.getSelected().iterator().next();
+ form.setCustomer(customer);
+ }
+});
+----
+
+In the listener, we simply take the Customer object of the selected row and pass it to
+the CustomerForm for editing. In the previous step, we added a side effect to the
+_setCustomer_ method that will bind the domain object to the corresponding fields
+and make it visible. If the selection is empty, we'll hide the form.
+
+To allow users to also create new customer records, we'll create a simple "Add
+customer button" to the top of the UI, right next to the _filtering_ composition
+we have already built from a CssLayout, a TextField and a Button. Introduce the new
+Button with a click listener, by adding the following lines to the _init_ method,
+right after where you introduced the _filtering_ composition:
+
+[source,java]
+----
+Button addCustomerBtn = new Button("Add new customer");
+addCustomerBtn.addClickListener(e -> {
+ grid.select(null);
+ form.setCustomer(new Customer());
+});
+----
+
+In the click listener, we first clear a possible selection from the grid and then
+instantiate a new Customer object and pass that to the form for editing.
+
+To add it beside our _filtering_ composition, we can use a HorizontalLayout to
+create a toolbar where we place both components. First, introduce a toolbar like
+this after the previously created _addCustomerBtn_:
+
+[source,java]
+----
+HorizontalLayout toolbar = new HorizontalLayout(filtering, addCustomerBtn);
+toolbar.setSpacing(true);
+----
+
+And, again, *replace* the line that populates your main layout to add the
+toolbar instead of just the filtering composition, which we just moved to the
+_toolbar_ layout.
+
+[source,java]
+----
+layout.addComponents(toolbar, main);
+----
+
+All planned features are now done. You can save the changes and play around with
+the application. If something went wrong, you can also download an example of
+https://github.com/vaadin/tutorial[the final application] and see what went wrong.
+
+== It works! What next?
+
+Congratulations! Users can now create, read, update and delete customer records
+stored in the demo backend and you have completed creating your first CRUD UI
+with Vaadin.
+
+If you are an experienced Java developer, you are probably already full of ideas of
+how you can use your existing skills and create new shiny web UIs for your
+existing Java apps. If you want more ideas of how to create full stack
+applications, you might, for example, go through the
+http://spring.io/guides/gs/crud-with-vaadin/[Creating CRUD UI with Vaadin] guide
+and create a bit similar UI with a real database backend implemented with Spring
+Data JPA. We have also collected a couple of other resources for an easy
+start in your Vaadin developer career.
+
+ * https://vaadin.com/docs/-/part/framework/introduction/intro-overview.html[Vaadin online documentation]
+ * http://spring.io/guides/gs/crud-with-vaadin/[Creating CRUD UI with Vaadin] - the tutorial for your first Vaadin application using a Spring based backend.
+ * https://github.com/mstahv/jpa-invoicer[Jave EE example app] - a Vaadin app example for creating invoices that uses Java EE backend, Apache DeltaSpike Data for simple JPA layer, OAuth2 based login, PDF generation etc.
+ * http://vaadin.com/directory[Directory] - a vast source of awesome Vaadin add-ons
+
+