Vaadin

Vaadin Best Practices

Best practices are procedures that are accepted or prescribed as being correct or most effective.
 
 
 
 
 
 
 
 
 

1. The tools

  • Java JDK 8
  • Latest Eclipse Mars
  • Vaadin 7.6.8
  • Tomcat Server 8

2. Introduction

In this example we are going to illustrate best practices used to make Vaadin applications. We are going to make a Vaadin example to illustrate these practices.

3. Prerequisites

  • JDK installed
  • Eclipse Mars installed and working
  • Vaadin plug-in installed
  • Tomcat 8 installed and running

4. Set up the project

In the file menu choose File -> New -> Other

01 New Project
1 New Project

Now from the list choose Vaadin 7 project

02 Vaadin Project
2 Vaadin Project

Click next and name your project then click finish.

5. The example

5.1 Make a design

The design is the blueprint of our program. It is better to invest some time making a good design and when the design is ready, start coding the application.
In our case we have an application that has a menu and three views, each button on the menu changes the view. We have a welcome view that displays a welcome label.
An input view to input some fields, and a view to show all the data.

3 Design
3 Design

5.2 Annotations

It is recommended to use annotations to define our servlet, because Vaadin uses annotations by default for convenience.
Convenience over configuration is a design pattern used to avoid huge configuration files and promotes flexibility.

Annotations

	@WebServlet(value = "/*", asyncSupported = true)
	@VaadinServletConfiguration(productionMode = false, ui = VaadinbestpracticesUI.class, widgetset = "com.example.vaadinbestpractices.widgetset.VaadinbestpracticesWidgetset")

5.3 Navigator

Use a navigator to change the views in the application. The navigator was created for this task. We use the navigator in our init application method.

5.3.1 Layout & content

In our init method, first we create the layout and the content panel to use with the navigator.

Layout & content

		final VerticalLayout layout = new VerticalLayout();
		layout.setMargin(true);
		setContent(layout);
		Panel contentPanel = new Panel("Main Panel");
		contentPanel.setSizeUndefined();

final VerticalLayout layout = new VerticalLayout(); Creates the layout.
layout.setMargin(true); Sets the margin of the layout.

setContent(layout); Sets the layout as the main layout.
Panel contentPanel = new Panel("Main Panel"); Creates a panel yo use with the navigator.

contentPanel.setSizeUndefined(); Sets the size of the panel.

5.3.2 Navigator views

We create the navigator and attach the views used in our application. In this case we have 3 views: welcome, input and data.

Navigators views

		new Navigator(this, contentPanel);
		getNavigator().addView(InputPage.NAME, InputPage.class);
		getNavigator().addView(WelcomePage.NAME, WelcomePage.class);
		getNavigator().addView(DataPage.NAME, DataPage.class);

new Navigator(this, contentPanel); Creates the navigator using the panel as a placeholder.
getNavigator().addView(InputPage.NAME, InputPage.class); Adds the input view to the navigator.

getNavigator().addView(WelcomePage.NAME, WelcomePage.class); Adds the welcome view to the navigator.
getNavigator().addView(DataPage.NAME, DataPage.class); Adds the data view to the navigator.

5.3.3 Menu listeners

We are going to navigate our application using a menu. Each time we click on a menu button the navigator changes the view. For each menu button we have a listener to change the view.

Menubar listeners

		MenuBar.Command welcome = new Command() {
			
			@Override
			public void menuSelected(MenuItem selectedItem) {
				getNavigator().navigateTo(WelcomePage.NAME);
			}
		};
		
		MenuBar.Command input = new Command() {
			
			@Override
			public void menuSelected(MenuItem selectedItem) {
				getNavigator().navigateTo(InputPage.NAME);
			}
		};

		MenuBar.Command data = new Command() {
			
			@Override
			public void menuSelected(MenuItem selectedItem) {
				getNavigator().navigateTo(DataPage.NAME);
			}
		};

MenuBar.Command welcome = new Command() Creates a new menu command welcome.
getNavigator().navigateTo(WelcomePage.NAME); Navigates to the welcome page.

MenuBar.Command input = new Command() Creates a new menu command input.
getNavigator().navigateTo(InputPage.NAME); Navigates to the input view.

MenuBar.Command data = new Command() Creates a new menu command data.
getNavigator().navigateTo(DataPage.NAME); Navigates to the data view.

5.3.4 Menu

We create the menu and attach the buttons to it. When a button is attached to the menu we use the menu command listener created before.

Main menu

		MenuBar mainMenu = new MenuBar();
		mainMenu.addItem("Welcome", FontAwesome.ARROW_CIRCLE_LEFT, welcome);
		mainMenu.addItem("Input", FontAwesome.WEIXIN, input);
		mainMenu.addItem("Data", FontAwesome.LIST, data);

MenuBar mainMenu = new MenuBar(); Creates a new menu bar.
mainMenu.addItem("Welcome", FontAwesome.ARROW_CIRCLE_LEFT, welcome); Add the welcome button to the menu.

mainMenu.addItem("Input", FontAwesome.WEIXIN, input); Add the input button to the menu.
mainMenu.addItem("Data", FontAwesome.LIST, data); Add the data button to the menu.

5.3.5 Navigator initial page

We redirect the navigator to the page we want to show when the application is started.

Navigator initial page

		layout.addComponent(mainMenu);
		layout.addComponent(contentPanel);
		getNavigator().navigateTo(WelcomePage.NAME);

layout.addComponent(mainMenu); Adds the menu to the layout.
layout.addComponent(contentPanel); Adds the content panel to the layout.

getNavigator().navigateTo(WelcomePage.NAME); Navigates to the welcome page when the application is loaded.

5.3.6 Welcome page

The welcome page is used as the initial page for the navigator.

Welcome page

public class WelcomePage extends VerticalLayout implements View {

	private static final long serialVersionUID = 1L;

	public static final String NAME = "welcomepage";
	
	public WelcomePage() {
		setMargin(true);
		setSpacing(true);
		Label welcome = new Label("Welcome");
		welcome.addStyleName("h1");
		addComponent(welcome);
	}

}

public class WelcomePage extends VerticalLayout implements View The welcome page used by the navigator must implements the view interface.
public static final String NAME = "welcomepage"; The id of the welcome page to use with the navigator.

setMargin(true); Sets the margin of the layout.
setSpacing(true); Sets the spacing of the layout.

Label welcome = new Label("Welcome"); Creates a label.
welcome.addStyleName("h1"); Adds a predefined style to the label.

addComponent(welcome); Adds the label to the layout.

5.4 Validate user input

The data entered by a user is prone to errors and mistakes and is sane to have a validation process in the input of the data.
We have a view with three input fields to show the validation process.
To validate our input fields we use the Vaadin validator.

5.4.1 Input form

Input form

		FormLayout inputForm = new FormLayout();
		inputForm.setMargin(true);
		inputForm.setSpacing(true);
		inputPanel.setContent(inputForm);

FormLayout inputForm = new FormLayout(); Creates the input form.
inputForm.setMargin(true); Sets the margin of the input form.

inputForm.setSpacing(true); Sets the spacing of the input form.
inputPanel.setContent(inputForm); Sets the input form as the content of the input panel.

5.4.2 Name field validator

Name Field

		TextField name = new TextField("Name");
		name.setNullSettingAllowed(true);
		name.setNullRepresentation("");
		name.addValidator(new StringLengthValidator("Name must have 3-15 characters lenght", 3, 15, true));
		name.setValidationVisible(true);
		inputForm.addComponent(name);

TextField name = new TextField("Name"); Creates a name text field.
name.setNullSettingAllowed(true); Allows null in the text field.

name.setNullRepresentation(""); Sets the null representation to a empty string.
name.addValidator(new StringLengthValidator("Name must have 3-15 characters lenght", 3, 15, true));
Adds the validator to the text field.
The validator checks that the string entered into the text field has a length greater than 3 and less than 15.
name.setValidationVisible(true); Sets the validator visible.
inputForm.addComponent(name); Add the text field to the form.

5.4.3 Surname field validator

Surname Field

		TextField surname = new TextField("Surname");
		surname.setNullSettingAllowed(true);
		surname.setNullRepresentation("");
		surname.addValidator(new StringLengthValidator("Surname must have 3-15 characters lenght", 3, 15, true));
		surname.setValidationVisible(true);
		inputForm.addComponent(surname);

TextField surname = new TextField("Surname"); Creates a text field to the surname.
surname.setNullSettingAllowed(true); Alows null in the text field.

surname.setNullRepresentation(""); Sets the null representation to a empty string.
surname.addValidator(new StringLengthValidator("Surname must have 3-15 characters lenght", 3, 15, true));
Adds the validator to the text field.
The validator checks that the string entered into the text field has a length greater than 3 and less than 15.
surname.setValidationVisible(true); Sets the validator visible.
inputForm.addComponent(surname); Add the text field to the form.

5.4.4 Age field validator

Age field

		TextField age = new TextField("Age");
		age.setNullRepresentation("0");
		age.addValidator(new IntegerRangeValidator("Age must be between 1 and 110", 1, 110));
		inputForm.addComponent(age);

TextField age = new TextField("Age"); Creates a text field for the age.
age.setNullRepresentation("0"); Sets the null representation to the “0” string.

age.addValidator(new IntegerRangeValidator("Age must be between 1 and 110", 1, 110));
Adds the validator to the field.
The value of the input must be an integer between 1 and 110.
inputForm.addComponent(age); Adds the text fiel to the form.

5.4.5 Age field validator

Validation buttons

		HorizontalLayout btLayout = new HorizontalLayout();
		Button btSave = new Button("Save");
		btLayout.addComponent(btSave);
		Button btClear = new Button("Clear");
		btLayout.addComponent(btClear);
		inputForm.addComponent(btLayout);

HorizontalLayout btLayout = new HorizontalLayout(); Creates a horizontal layout for the buttons.
Button btSave = new Button("Save"); Creates a button for save the form data.

btLayout.addComponent(btSave); Adds the button to the layout.
Button btClear = new Button("Clear"); Creates a new button to clear the fields.

btLayout.addComponent(btClear); Adds the clear button to the layout.
inputForm.addComponent(btLayout); Adds the button layout to the form.

5.4.6 Validation process

Checks if the fields are empty

		btSave.addClickListener(new ClickListener() {
			
			@Override
			public void buttonClick(ClickEvent event) {
				if(!name.isEmpty() && !surname.isEmpty() && !age.isEmpty()){

				}else{
					Notification.show("All fields must be filled");
				}

Checks that all fields have a value otherwise it shows a notification.

Try to validate

					Boolean save = true;
					try{
						name.validate();
						
					}catch(InvalidValueException e){
						save = false;
					}
					
					try{
						surname.validate();
						
					}catch(InvalidValueException e){
						save = false;
					}

					try{
						age.validate();
						
					}catch(InvalidValueException e){
						save = false;
					}

Tries to validate the fields. A boolean is used to keep the status of the validation process. If any validation fails we set save to false.

Save click listener

					if(save){
						VaadinbestpracticesUI.dataBean.addBean(
								new DataBean(name.getValue(), surname.getValue(), Integer.valueOf(age.getValue())));
						Notification.show("Data saved!");
						name.setValue("");
						surname.setValue("");
						age.setValue("0");
						btSave.setComponentError(null);
					}

if(save) We check the boolean to save.
VaadinbestpracticesUI.dataBean.addBean(new DataBean(name.getValue(), surname.getValue(), Integer.valueOf(age.getValue())));
We create a bean with the new data.
Notification.show("Data saved!"); Notifies that the data is saved.
name.setValue(""); Clears the name field.

surname.setValue(""); Clears the surname field.
age.setValue("0"); Clears the age field with the null value.

5.4.7 Clear fields

java

		btClear.addClickListener(new ClickListener() {
			
			@Override
			public void buttonClick(ClickEvent event) {
				name.clear();
				surname.clear();
				age.clear();
			}
		});

name.clear(); Clears the name.
surname.clear(); Clears the surname.
age.clear(); Clears the age.

5.5 Use containers in fields

The container allow us to bind our input fields to a data type and help in the validation process.

5.5.1 Property sets

java

		PropertysetItem fProperties = new PropertysetItem();
		fProperties.addItemProperty("nameValidator", new ObjectProperty(""));
		fProperties.addItemProperty("surnameValidator", new ObjectProperty(""));
		fProperties.addItemProperty("integerValidator", new ObjectProperty(0));

PropertysetItem fProperties = new PropertysetItem(); Creates a property set.
fProperties.addItemProperty("nameValidator", new ObjectProperty("")); Adds the name property.

fProperties.addItemProperty("surnameValidator", new ObjectProperty("")); Adds the surname property.
fProperties.addItemProperty("integerValidator", new ObjectProperty(0) Adds the age property.

5.5.2 Field groups

java

		FieldGroup fGroup = new FieldGroup(fProperties);
		fGroup.bind(name, "nameValidator");
		fGroup.bind(surname, "surnameValidator");
		fGroup.bind(age, "integerValidator");

FieldGroup fGroup = new FieldGroup(fProperties); Creates a field group.
fGroup.bind(name, "nameValidator"); Binds the name text field to the name property.

fGroup.bind(surname, "surnameValidator"); Binds the surname text field to the surname property.
fGroup.bind(age, "integerValidator"); Binds the age text field to the age property.

5.6 Separate the UI from the data

Separation of the data from the UI allow us to change the UI or the data store without affecting each other.

In the image the UI, the datasets and the database are in different layers.
If you change any of these three pieces you only have to define the same interfaces to communicate each other.
The change of one layer doesn’t have to affect any other layer. If you want to change the database from MySQL to PostgreSQL for example, this change is transparent to the UI code.

4 Design pattern
4 Design pattern

Data

public class DataBean implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String  name;
	private String  surname;
	private Integer age;
	
	public DataBean(String pName, String pSurname, Integer pAge) {
		this.name = pName;
		this.surname = pSurname;
		this.age = pAge;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSurname() {
		return surname;
	}

	public void setSurname(String surname) {
		this.surname = surname;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

}

This is a standard java class that extends serializable.
This class has three fields to store the name, the surname and the age with its getters and setters.

Data View

	public static final String NAME = "datapage";

	public DataPage() {
		Table dataTable = new Table("Data Table", VaadinbestpracticesUI.dataBean);
		dataTable.setVisibleColumns(new Object[]{"name", "surname", "age"});
		dataTable.setHeight("200px");
		addComponent(dataTable);
	}

public static final String NAME = "datapage"; Creates the id of the data view.
Table dataTable = new Table("Data Table", VaadinbestpracticesUI.dataBean);
Creates a table to show all the records we have loaded.
The table is using the container as a data source.
dataTable.setVisibleColumns(new Object[]{"name", "surname", "age"}); Sets the visible columns.
dataTable.setHeight("200px"); Sets the height of the table.

addComponent(dataTable); Adds the table to the layout.

5.7 Deploy on https

If our application is going to be on a public domain is better to deploy it using http secure protocol.
Https encrypts our connection protecting us for some kind of attacks that could compromise our data.

6. The complete source code

6.1 VaadinbestpracticesUI.java

VaadinbestpracticesUI.java

package com.example.vaadinbestpractices;

import javax.servlet.annotation.WebServlet;

import com.example.vaadinbestpractices.data.DataBean;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.navigator.Navigator;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.Command;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Panel;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings("serial")
@Theme("vaadinbestpractices")
public class VaadinbestpracticesUI extends UI {
	
	public static BeanContainer dataBean;	
	
	@WebServlet(value = "/*", asyncSupported = true)
	@VaadinServletConfiguration(productionMode = false, ui = VaadinbestpracticesUI.class, widgetset = "com.example.vaadinbestpractices.widgetset.VaadinbestpracticesWidgetset")
	public static class Servlet extends VaadinServlet {
	}

	@Override
	protected void init(VaadinRequest request) {
		final VerticalLayout layout = new VerticalLayout();
		layout.setMargin(true);
		setContent(layout);
		Panel contentPanel = new Panel("Main Panel");
		contentPanel.setSizeUndefined();
		dataBean = new BeanContainer(DataBean.class);
		dataBean.setBeanIdProperty("name");
		
		new Navigator(this, contentPanel);
		getNavigator().addView(InputPage.NAME, InputPage.class);
		getNavigator().addView(WelcomePage.NAME, WelcomePage.class);
		getNavigator().addView(DataPage.NAME, DataPage.class);

		MenuBar.Command welcome = new Command() {
			
			@Override
			public void menuSelected(MenuItem selectedItem) {
				getNavigator().navigateTo(WelcomePage.NAME);
			}
		};
		
		MenuBar.Command input = new Command() {
			
			@Override
			public void menuSelected(MenuItem selectedItem) {
				getNavigator().navigateTo(InputPage.NAME);
			}
		};

		MenuBar.Command data = new Command() {
			
			@Override
			public void menuSelected(MenuItem selectedItem) {
				getNavigator().navigateTo(DataPage.NAME);
			}
		};

		MenuBar mainMenu = new MenuBar();
		mainMenu.addItem("Welcome", FontAwesome.ARROW_CIRCLE_LEFT, welcome);
		mainMenu.addItem("Input", FontAwesome.WEIXIN, input);
		mainMenu.addItem("Data", FontAwesome.LIST, data);
		
		layout.addComponent(mainMenu);
		layout.addComponent(contentPanel);
		getNavigator().navigateTo(WelcomePage.NAME);
	}

}

6.2 WelcomePage.java

WelcomePage.java

package com.example.vaadinbestpractices;

import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;

public class WelcomePage extends VerticalLayout implements View {

	private static final long serialVersionUID = 1L;

	public static final String NAME = "welcomepage";
	
	public WelcomePage() {
		setMargin(true);
		setSpacing(true);
		Label welcome = new Label("Welcome");
		welcome.addStyleName("h1");
		addComponent(welcome);
	}

	@Override
	public void enter(ViewChangeEvent event) {

	}

}

6.3 InputPage.java

InputPage.java

package com.example.vaadinbestpractices;

import com.example.vaadinbestpractices.data.DataBean;
import com.google.appengine.api.memcache.InvalidValueException;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.data.validator.IntegerRangeValidator;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

@SuppressWarnings("serial")
public class InputPage extends VerticalLayout implements View {

	public static final String NAME = "inputpage";
	
	public InputPage() {
		Panel inputPanel = new Panel("Input data");
		inputPanel.setSizeUndefined();
		addComponent(inputPanel);
		
		PropertysetItem fProperties = new PropertysetItem();
		fProperties.addItemProperty("nameValidator", new ObjectProperty(""));
		fProperties.addItemProperty("surnameValidator", new ObjectProperty(""));
		fProperties.addItemProperty("integerValidator", new ObjectProperty(0));
		
		FormLayout inputForm = new FormLayout();

		TextField name = new TextField("Name");
		name.setNullSettingAllowed(true);
		name.setNullRepresentation("");
		name.addValidator(new StringLengthValidator("Name must have 3-15 characters lenght", 3, 15, true));
		name.setValidationVisible(true);
		inputForm.addComponent(name);

		TextField surname = new TextField("Surname");
		surname.setNullSettingAllowed(true);
		surname.setNullRepresentation("");
		surname.addValidator(new StringLengthValidator("Surname must have 3-15 characters lenght", 3, 15, true));
		surname.setValidationVisible(true);
		inputForm.addComponent(surname);

		TextField age = new TextField("Age");
		age.setNullRepresentation("0");
		age.addValidator(new IntegerRangeValidator("Age must be between 1 and 110", 1, 110));
		inputForm.addComponent(age);
		
		HorizontalLayout btLayout = new HorizontalLayout();
		Button btSave = new Button("Save");
		btLayout.addComponent(btSave);
		Button btClear = new Button("Clear");
		btLayout.addComponent(btClear);
		inputForm.addComponent(btLayout);
		
		btSave.addClickListener(new ClickListener() {
			
			@Override
			public void buttonClick(ClickEvent event) {
				if(!name.isEmpty() && !surname.isEmpty() && !age.isEmpty()){
					Boolean save = true;
					try{
						name.validate();
						
					}catch(InvalidValueException e){
						save = false;
					}
					
					try{
						surname.validate();
						
					}catch(InvalidValueException e){
						save = false;
					}

					try{
						age.validate();
						
					}catch(InvalidValueException e){
						save = false;
					}
					
					if(save){
						VaadinbestpracticesUI.dataBean.addBean(
								new DataBean(name.getValue(), surname.getValue(), Integer.valueOf(age.getValue())));
						Notification.show("Data saved!");
						name.setValue("");
						surname.setValue("");
						age.setValue("0");
						btSave.setComponentError(null);
					}
				}else{
					Notification.show("All fields must be filled");
				}
			}
		});
		
		btClear.addClickListener(new ClickListener() {
			
			@Override
			public void buttonClick(ClickEvent event) {
				name.clear();
				surname.clear();
				age.clear();
			}
		});
		
		FieldGroup fGroup = new FieldGroup(fProperties);
		fGroup.bind(name, "nameValidator");
		fGroup.bind(surname, "surnameValidator");
		fGroup.bind(age, "integerValidator");
		
		inputForm.setMargin(true);
		inputForm.setSpacing(true);
		inputPanel.setContent(inputForm);
	}

	@Override
	public void enter(ViewChangeEvent event) {
		
	}

}

6.4 DataPage.java

DataPage.java

package com.example.vaadinbestpractices;

import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;

public class DataPage extends VerticalLayout implements View {

	private static final long serialVersionUID = 1L;

	public static final String NAME = "datapage";

	public DataPage() {
		Table dataTable = new Table("Data Table", VaadinbestpracticesUI.dataBean);
		dataTable.setVisibleColumns(new Object[]{"name", "surname", "age"});
		dataTable.setHeight("200px");
		addComponent(dataTable);
	}

	@Override
	public void enter(ViewChangeEvent event) {

	}

}

6.5 DataBean.java

DataBean.java

package com.example.vaadinbestpractices.data;

import java.io.Serializable;

public class DataBean implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private String  name;
	private String  surname;
	private Integer age;
	
	public DataBean(String pName, String pSurname, Integer pAge) {
		this.name = pName;
		this.surname = pSurname;
		this.age = pAge;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getSurname() {
		return surname;
	}

	public void setSurname(String surname) {
		this.surname = surname;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

}

7. Running the example

Right click on the project folder and choose Run as -> Run on server choose Tomcat 8 server and click finish.

8. Results

8.1 Welcome view

This is the start page. Every time you open the application page, this page is shown.

5 Welcome View
5 Welcome View

8.2 Input view

In this page we can add records to our example. Here we validate the fields and then store the data into a container.

6 Input View
6 Input View

8.3 Input view

In this view, we retrieve all the records from the container and shown them into a table.

7 Data View
7 Data View

9. Download the Source Code

This was an example of: Vaadin Best Practices.

Download
You can download the Eclipse project here: VaadinBestPractices

Jesus Boadas

I'm a self taught programmer, I began programming back in 1991 using an IBM A10 mainframe with Pascal an Assembler IBM 360/70 emulator and Turbo C on a X86 PC, since that I work for the banking industry with emerging technologies like Fox Pro, Visual Fox Pro, Visual Basic, Visual C++, Borland C++, lately I moved out to the Airline industry, leading designing and programming in-house web applications with Flex, Actionscript, PHP, Python and Rails and in the last 7 years I focused all my work in Java, working on Linux servers using GlassFish, TomCat, Apache and MySql.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button