Songs of Vaadin

Vaadin to demon pochodzący z fińskiej mitologii. Ma on postać renifera górskiego – boga przodka. Tyle tytułem wstępu.
Vaadin to też bardzo fajny framework UI oparty o GWT. Ważne słowo „opartu o” nie jest to nakładka na GWT, która tylko dostarcza komponentów, ale jest to całkowicie nowy pomysł, który zawiera to czego brakuje w GWT.

Jak dzielimy narzędzia

Pisząc aplikację zazwyczaj posiłkujemy się specjalnymi bibliotekami, zawierającymi różne komponenty, jak i gotowe rozwiązania pozwalające tworzyć aplikacje. Biblioteki te co do zasady nazywamy frameworkami. Nie jest to do końca słuszne dla wszystkich rozwiązań.
Frameworki to biblioteki takie jak np. Spring, które pozwalają na tworzenie aplikacji, ale pomimo najlepszych chęci twórców końcowy wynik jest silnie zintegrowany z frameworkiem. Można to porównać do obudowywania szkieletu naszą tkanką. Bez szkieletu wszystko się posypie.
Rusztowania to biblioteki wspomagające tworzenie aplikacji np. Grails, które po zakończeniu można w znacznej mierze usunąć z finalnego projektu i nie będzie to nas bolało. Zazwyczaj jedynym elementem wymaganym jest niewielka biblioteka dostarczająca klasy narzędziowe, ale można też obyć się bez niej.
GWT należy do trzeciej grupy. Nazywam ją „składem budowlanym a’la ikea”. W ramach biblioteki dostajemy stertę cegieł, desek, kilka worków cementu oraz instrukcję jak to wszystko można łączyć. Przypomina to wielkie pudło klocków Lego, z których możemy wybudować co nam się podoba. Niestety w IT oznacza to, że każdą trochę bardziej zaawansowaną funkcjonalność trzeba machać ręcznie lub szukać bibliotek.

Wady GWT

Najpoważniejszą wadą GWT jest jednak nieuwolnienie programistów od konieczności korzystania z elementów powiązanych z webem. Nadal musimy rzeźbić plik web.xml, nadal trzeba uważać co i jak przekazujemy do klienta. Do tego musimy użerać się z niekompatybilnością bibliotek. Na całe szczęście duża część kodu jest otwarta i można sobie poprawić to i owo.
Kolejną wadą jest kompilator Java2JavaScript. Gdy pojawił się na rynku to wszyscy byli nim zauroczeni. Pozwalał na uwolnienie się od grzebania w dziwnym języku jakim jest JS i przeniesienie zadań związanych z budową UI na programistów. Ci mając doświadczenie ze Swingiem mogli w naturalny sposób tworzyć interfejs użytkownika. Niestety szybko okazało się, że swoboda tworzenia jest mocno ograniczona. Nadal istniała separacja pomiędzy klientem i serwerem, najlepiej widoczna w postaci nazewnictwa pakietów. Do tego kompilator nie potrafił poradzić sobie z przeniesieniem wszystkich klas ze standardowego API Javy do przeglądarki. Dlaczego nie można było używać Calendar, a musieliśmy użerać się z Date? Czemu nie przeniesiono wszystkich wyjątków? Powodowało to konieczność namnażania bytów w ramach wzorców Value Object i DTO i to nie dla jakiś super skomplikowanych obiektów, ale dla standardowych elementów języka.

Gdzie jest Vaadin?

Vaadin jest oparty o GWT. Wykorzystuje tą bibliotekę ponieważ jest ona świetna do generowania elementów UI. Pozwala też na wykorzystanie już gotowych widgetów GWT w projekcie. Jeżeli jednak nie chcemy mieć nic wspólnego z GWT to nie zobaczymy ani linijki jego kodu.
Co to oznacza? Vaadin jest znacznie lepszym odpowiednikiem Swinga niż GWT. Separacja pomiędzy UI, a logiką jest bardziej naturalna, bliższa znanemu z okienek sposobowi zarządzania przepływem.

Prosta aplikacja

Przykładowa aplikacja będzie demonstrować główne założenie Vaadin, czyli zdjęcie z barków programisty konieczności dbania o plik web.xml. Zrobimy bardzo prostą rzecz. Formularz z jednym polem, którego zawartość będzie zapisywana do logu po stronie serwera.
Zaczniemy od wygenerowania prostego projektu Vaadin za pomocą Mavena. Jest to bardzo proste. Twórcy dostarczyli nawet klika różnych archetypów. Różnią się one szczegółami, ale na obecnym etapie nie jest to istotne. Użyję vaadin-archetype-clean. Poniżej skrypcik ułatwiający to zadanie. Pierwszy parametr grupa, drugi nazwa artefaktu.

Listing 1. Tworzenie aplikacji Vaadin – skrypt

#!/bin/bash

mvn archetype:generate -DarchetypeGroupId=com.vaadin -DarchetypeArtifactId=vaadin-archetype-clean -DarchetypeVersion=LATEST -DgroupId="$1" -DartifactId="$2" -Dversion=1.0 -Dpackaging=war

Po zaimportowaniu projektu do IDE mamy możliwość popatrzenia na plik pom.xml. Mój zawiera dodatkowe wpisy związane z JPA. Racz je zignorować.

Listing 2. Plik pom.xml



	4.0.0
	pl.koziolekweb.blog.vaadin
	first-vaadin-example
	war
	1.0
	Vaadin Web Application

	
		UTF-8
	

	
		
			
				org.apache.maven.plugins
				maven-compiler-plugin
				
					1.5
					1.5
				
			

			
			

			
			
				org.mortbay.jetty
				maven-jetty-plugin
				6.1.19
				
					
						
							jetty.port
							23030
						
					
					9966
					first-vaadin-example
					
					0
					
					
						/first-vaadin-example
						
							
							
							src/main/webapp,${project.build.directory}/${project.build.finalName}
							
						
					
				
			

			
				org.apache.maven.plugins
				maven-eclipse-plugin
				2.8
				
					true
					true
				
				
					
						eclipse
						clean
						
							clean
							eclipse
						
					
				
			
		
	

	
		
			vaadin-snapshots
			http://oss.sonatype.org/content/repositories/vaadin-snapshots/
			
			
				false
			
			
				true
			
		
		
			jboss
			http://repository.jboss.org/maven2
		
	

	

	
		
			com.vaadin
			vaadin
			6.2.0
		
		
		

		
			hibernate
			hibernate3
			3.2.4.SP1
		
		
			hibernate-annotations
			hibernate-annotations
			3.3.0.GA
		
		
			hibernate-commons-annotations
			hibernate-commons-annotations
			3.0.0.GA
		
		
			hibernate-entitymanager
			hibernate-entitymanager
			3.3.1.GA
		
		
			javax.persistence
			persistence-api
			1.0
		
		
			javax.transaction
			jta
			1.1
		
		
			hsqldb
			hsqldb
			1.8.0.10
		
	

Na koniec jeszcze plik aplikacji.

Listing 3. Aplikacja Vaadin

/*
 * Copyright 2009 IT Mill Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package pl.koziolekweb.blog.vaadin;

import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.Window;

/**
 * The Application's "main" class
 */
@SuppressWarnings("serial")
public class MyVaadinApplication extends Application
{
    private Window window;

    @Override
    public void init()
    {
        window = new Window("My Vaadin Application");
        setMainWindow(window);
        window.addComponent(new Button("Click Me"));
    }
    
}

Odpalamy jettego w celach testowych. Domyślnie na porcie 8080 u mnie na 23030, bo na 8080 mam Tomcata. Sprawdzamy działa.
Teraz czas na nasz formularz. Vaadin dostarcza własny zestaw komponentów. Mają własną hierarchię, ale jak przejdziemy do kodu źródłowego to zobaczymy, że wykorzystywane są komponenty GWT. Dla własnego zdrowia psychicznego nie wnikajmy jednak jak Vaadin robi swoją magię. Ważne, że działa.
Nowa wersja klasy:

Listing 4. Wysyłamy informację

/*
 * Copyright 2009 IT Mill Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package pl.koziolekweb.blog.vaadin;

import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

/**
 * The Application's "main" class
 */
public class MyVaadinApplication extends Application {
	
	private static final long serialVersionUID = 1L;
	private Window window;

	@Override
	public void init() {
		window = new Window("My Vaadin Application");
		setMainWindow(window);
		final TextField messageTfd = new TextField("Message");
		messageTfd.setColumns(25);
		Button sendBtn = new Button("Click Me");

		sendBtn.addListener(new ClickListener() {
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				System.out.println(messageTfd.getValue());
			}
		});
		window.addComponent(messageTfd);
		window.addComponent(sendBtn);
	}

}

Wygląda niewinnie. Odpalamy jettego wpisujemy wiadomość, klikamy i…

Listing 5. Zawartość logu

[INFO] Started Jetty Server
=================================================================
Vaadin is running in DEBUG MODE.
Add productionMode=true to web.xml to disable debug features.
To show debug window, add ?debug to your application URL.
=================================================================

Wiadomość

Działa!!!

Wow! Nie napisałem ani linijki jeśli chodzi o komunikację. Nie otworzyłem nawet pliku web.xml, a mam możliwość logowania informacji na serwer. Prawda, że bajer? Teraz czas na najbardziej widowiskowy bajer Vaadin. Nie będę opisywał co i jak, ale chyba załapiecie o co w tym chodzi:

Listing 6. Magia 😉

/*
 * Copyright 2009 IT Mill Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package pl.koziolekweb.blog.vaadin;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

import com.vaadin.Application;
import com.vaadin.terminal.StreamResource;
import com.vaadin.terminal.UserError;
import com.vaadin.terminal.StreamResource.StreamSource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.TextField;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

/**
 * The Application's "main" class
 */
public class MyVaadinApplication extends Application {

	private static final long serialVersionUID = 1L;

	private Window window;

	private Button sendBtn;

	private TextField messageTfd;

	private Embedded image;

	@Override
	public void init() {
		window = new Window("My Vaadin Application");
		setMainWindow(window);
		messageTfd = new TextField("Message");
		messageTfd.setColumns(5);
		sendBtn = new Button("Click Me");

		sendBtn.addListener(new ClickListener() {
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				messageTfd.setComponentError(null);
				if (!((String) messageTfd.getValue()).matches("^\\d*$")) {
					messageTfd.setComponentError(new UserError("Digits only!"));
					return;
				}
				else {
					int rgb = 0;
					try {
						rgb = new Integer(((String) messageTfd.getValue())
								.trim()).intValue();
						if (rgb > 255 || rgb < 0) {
							messageTfd.setComponentError(new UserError(
									"Use number between 0 and 255"));
							return;
						}
					} catch (Exception e) {
					}
					StreamResource.StreamSource picasso = new Picasso(rgb);
					StreamResource imageresource = createStreamResource(picasso);
					if (image != null) {
						window.removeComponent(image);
					}
					image = new Embedded("Image title", imageresource);
					window.addComponent(image);
				}
			}
		});
		window.addComponent(messageTfd);
		window.addComponent(sendBtn);
	}

	public static void log(Integer rgb) {
		System.out.println(rgb);
	}

	private StreamResource createStreamResource(
			StreamResource.StreamSource imagesource) {
		return new StreamResource(imagesource, "myimage.png", this);
	}

}

class Picasso implements StreamSource {
	private ByteArrayOutputStream imagebuffer = null;
	private Color color = Color.RED;

	public Picasso(int rgb) {
		this.color = new Color(rgb, rgb, rgb);
	}

	public InputStream getStream() {
		BufferedImage image = new BufferedImage(200, 200,
				BufferedImage.TYPE_INT_RGB);
		Graphics drawable = image.getGraphics();
		drawable.setColor(Color.WHITE);
		drawable.fillRect(0, 0, 200, 200);
		drawable.setColor(color);
		drawable.drawString("Vaadin", 20, 20);

		try {
			imagebuffer = new ByteArrayOutputStream();
			ImageIO.write(image, "png", imagebuffer);

			return new ByteArrayInputStream(imagebuffer.toByteArray());

		} catch (IOException e) {
			return null;
		}

	}
}

Podsumowując. Vaadin jest obecnie chyba najwygodniejszym znanym mi narzędziem pozwalającym na pracę przy webowym UI tak jak ze Swingiem. Zapraszam na moją prezentację o Vaadin w ramach WJUG 20 kwietnia o 18.00. Pokażę kilka innych elementów m.n. integrację ze Springiem.

17 myśli na temat “Songs of Vaadin

  1. W końcu wprowadzenie na miarę dopasowaną do mnie! Dzięki Koziołek. Vaadin przypomina mi Wicketa, ale znaczącą (?) różnicą jest UI – w Wicket to po prostu JavaScript, a w Vaadin to GWT, który również staje się JavaScriptem. Krok pośredni między Vaadin a aplikacją docelową jest przejście przez GWT. Czy to dobre rozumowanie? Nie znam Vaadina, ale po Twoim krótkim wpisie mam wrażenie, jakbym bawił się nim od lat 🙂 Wspaniały sposób, aby zaprosić zainteresowanych więcej na spotkanie. Masz styl!

  2. Po przeczytaniu Twojego postu udałem się na homepage Vaadin’a i ku mojej uciesze szybko znalazłem odpowiedzi na pierwsze pytania i wydaje mi się, że biblioteka/framework jest warta uwagi. Po wejściu na stronę z komponentami widać, że Vaadin posklejał z cegieł i cementu parę nowych tworów, które wcześniej trzeba było „murować” samemu. A jeśli komunikacja z serwerem będzie choć w połowie tak łatwa jak się wydaję to pewnie dojdzie mi w CV punkt z Vaadinem 🙂 … szkoda, że ta Wawa tak daleko bo chętnie posłuchałbym Twojej prezentacji. Dzięki za wpis 🙂

  3. @Kędzior, będzie nagranie jak chłopaki nie zapomną o kamerze. Jacku?

    @Jacek, Nie za bardzo rozumiem pytanie. Używając Vaadin nie widzimy GWT, ale gdzieś głęboko w kodzie jest ono wykorzystywane. Trochę to tak jak z SWT i WinForms pod windą/GTK w linuxie. Korzystamy z SWT, które w magiczny sposób tłumaczy nasz javowy kod na coś blisko systemu. Co, jak, gdzie to mało istotne.

    BTW właśnie integruję ze springiem.

  4. Przeczytalem, obejrzalem, calkiem fajne. Tylko caly czas nie wiem dlaczego programisci Java tak sie boja tego JavaScriptu. Moim zdaniem sam JS (opakowany bibliotekami do niego) daje o wiele wieksze mozliwosci niz „posrednie” frameworki. Ale to byc moze wina tego, ze ja z webdeveloperskim zapleczem 🙂

    PS. Jak juz pisalem u siebie postaram sie pojawic na WJUGu.
    PS2. Dodalbys mnie do blogrolla 🙂

  5. Niechęć do JS wynika z jego toporności. Tak naprawdę dopiero od niedawna są jakieś sensowne biblioteki, a i sama szybkość JS wzrosła. Poza tym chyba każdy lubi mieć porządek w projekcie. Niech zatem jak już muszę używać JS to niech będzie to z poziomu Javy, a jak chcielibyśmy z poziomu innego narzędzia to niech robi to webmajster.

  6. Ja tam JS lubię, i jakoś toporny nie wydaje mi się wcale. Mam natomiast pytanie. Z tego co rozumiem, ten kawałek kodu w listenerze przycisku:

    System.out.println(messageTfd.getValue());

    wysłał nam wiadomość na serwer, tak? Czy to oznacza że obsługa każdego zdarzenia UI odbywa się na serwerze? Bo jak tak to trochę słabo, w GWT można się bawić z klientem w ogóle z serwerem się nie kontaktując.

    Czy w Vaadin też możnaby tak obsłużyć zdarzenie, że cała akcja odbywałaby się w kliencie, bez kontaktu z serwerem?

  7. Dobre pytanie… muszę sprawdzić, ale chyba jest tak, że Vaadin potrafi wykryć czy potrzeba komunikacji czy nie.

  8. Sprawdziłem. Vaadin obsługuje wszystkie zdarzenia po stronie serwera, ale sposób w jaki to robi jest bardzo ciekawy. Otóż odsyłana jest wiadomość o zmianie stanu ekranu. Prowadzi to oczywiście do pewnego narzutu w komunikacji w porównaniu z czystym GWT, ale to jest mała wada.

  9. Dlatego na Javarsowię zgłoszę się z prezentacją na temat wyboru narzędzi i frameworków 🙂

  10. Fajna sprawa ten Vaadin. Pamiętam, że w GWT najbardziej irytującą sprawą była właśnie komunikacja klient-server. Co prawda google udostępniło swój protokół RPC, ale przydałoby się coś prostrzego. DTO również do wygodnych rozwiązań nie należy, w sumie to jest chyba już anty-wzorzec.

    Jak wygląda sprawa dodatkowych bibliotek zawierających gotowe komponenty? W GWT co prawda mamy do dyspozycji kilka rozwiązań jak Ext-JS, Gwt-Ext, GWT-Mozaic itp. ale każde z nich ma jedną wadę.. Po załadowaniu do naszej aplikacji tempo pracy zwalnia. Z małej zwinnej aplikacyjki robi się toporna masa obfruscowanego JavaScriptu, który musi być „przemielony” przez klienta.

  11. Jeszcze tego nie rozpracowywałem, ale Vaadin pozwala na dodawanie własnych komponentów GWT. Chyba nawet jest to w miarę proste 😉 Jednak jest to do zbadania na po świętach.

  12. Czy mógłbyś napisać coś więcej na temat spostrzeżeń podczas pracy z Vaadinem? Co Was pozytywnie zaskoczyło? Jakie ujawniły się wady? Jak przypuszczam masz już pewne przemyślenia na jego temat. Ja natomiast rozważam go w kolejnym projekcie. Mam już powoli dość JSF, jego konfiguracji etc.

  13. Zobaczę jak będe stał z czasem po weekendzie. Chodzi mi po głowie integracja Vaadin + Spring DM. Samo Vaadin ma swoje myki, o których na razie nie będę pisał, bo się z nimi użeram…

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax