Pisząc sobie w Vaadin szybko możemy dość do wniosku, że standardowa biblioteka komponentów jest bogata, ale nie daje nam takich możliwości jakie byśmy chcieli. Bardzo często jest też tak, że przychodzi klient i mówi nam, że ma jakiś komponent GWT, który koniecznie musi zintegrować z naszym projektem… cóż życie jest usłane różami i prędzej czy później się ukujemy w stopę…
Omówię tu dwa problemy. Pierwszy to tworzenie własnych komponentów na bazie już istniejącego zestawu jaki dostarcza Vaadin. Drugi to integracja komponentu GWT.

Ciasne ale własne

Vaadin dostarcza nam wszystkie komponenty znane z GWT plus kilka własnych m.n. kalendarz, formularz logowania czy całkiem fajne, ale ciężkie w zrozumieniu drzewka. My chcemy jednak stworzyć własny komponent, który będzie wykorzystywał te elementy. Okazuje się, że jest to bardzo proste. Wystarczy, że rozszerzymy klasę CustomComponent i możemy już działać.

Listing 1. prosty komponent

import java.util.Date;

import com.vaadin.terminal.Sizeable;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.DateField;
import com.vaadin.ui.Panel;

public class MyCustomComponent extends CustomComponent {

	private static final long serialVersionUID = 1L;
	private Panel panel;
	private DateField dateField;

	public MyCustomComponent() {
		super();

		createElements();
		postConstruct();
		buildComponentTree();

		setCompositionRoot(panel);
	}

	private void buildComponentTree() {
		panel.addComponent(dateField);
	}

	private void postConstruct() {
		panel.setWidth(Sizeable.SIZE_UNDEFINED, 0);
		setWidth(Sizeable.SIZE_UNDEFINED, 0);
		dateField.setDateFormat("dd/MM/yyyy");
	}

	private void createElements() {
		panel = new Panel("Menu Panel");
		dateField = new DateField("Wybierz datę", new Date());
	}

}

Metoda ta ma swoje zalety. Po pierwsze jest bardzo szybka i intuicyjna. Mamy gotowe klocki i budujemy zamek. Po zbudowaniu dostarczamy gotowy do aplikacji. Jako, że korzystamy tylko z komponentów Vaadin to nie ma miejsca proces kompilacji za pomocą kompilatora GWT. Nie musimy też nic konfigurować w pom.xml. Wadą tego rozwiązania jest jego stosunkowo mała elastyczność w ramach świata webowego. Widget GWT można swobodnie przenosić pomiędzy różnymi projektami GWT, a i od biedy zapiąć do strony w php. Z komponentem Vaadin niestety tego nie zrobimy.
Skoro Vaadin nas ogranicza może spróbujmy wpiąć komponent GWT.

Wpinanie komponentu GWT

Tu zaczyna się mały hardcore. Generalnie Vaadin działa na zasadzie przesyłania pomiędzy klientem, a serwerem stanu ekranu. Wszystkie akcje odbywają się na serwerze, a u klienta odbywa się tylko serializacja rządań i deserializacja wyników. W przypadku GWT mechanizm ten jest znacznie bardziej elastyczny. Zarówno po stronie klienta jak i serwera można umieścić akcje biznesowe. Inny jest też model komunikacji. Vaadin wykorzystuje JSON, GWT XMLa.
Na cale szczęście na chwilę obecną zarówno plugin do Eclipse jak i do Mavena generuje automatycznie dodatkowe pliki związane z GWT. My przyjrzymy się przez chwilę architekturze całego rozwiązania.

GWT bez GWT, czyli Vaadin

Mamy komponent GWT (dowolny, bo Vaadin własne komponenty obsługuje w identyczny sposób):

Listing 2. prosty komponent GWT

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;

public class MyComponentGWT extends Composite {

	protected String random;

	protected Label label = new Label();

	private Button button = new Button("Clik me");

	private VerticalPanel panel = new VerticalPanel();

	public MyComponentGWT() {

		sinkEvents(Event.ONCLICK);
		button.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				setRandom(Math.random()*1000 + "");
			}
		});
		panel.add(label);
		panel.add(button);
		initWidget(panel);
	}

	protected void setLabelText(String t) {
		label.setText(t);
	}

	protected void setRandom(String text) {
		label.setText(text);
	};
}

i teraz chcemy umieścić go w aplikacji Vaadin. Dla uproszczenia zakładam, że logika będzie w tym przypadku odbywać się po stronie klienta. Jeżeli logika jest po stronie serwera i jest realizowana bezpośrednio w serwlecie to wystarczy odpowiednio skonfigurować web.xml.
Pierwszym krokiem jest stworzenie klasy VMyComponentGWT, która będzie rozszerzała MyComponentGWT i implementowała interfejs Paintable. Klasa ta jest klasą przesłaniającą i w razie konieczności pozwala na głębszą integrację to znaczy na przesyłanie informacji pomiędzy komponentami GWT i Vaadin. My sobie to na razie darujemy.

Listing 3. Klasa łącząca GWT i Vaadin

import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;

public class VMyComponentGWT extends MyComponentGWT implements Paintable {

	public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
	}

}

Zgodnie z konwencją przyjętą przez twórców Vaadin nazwa klasy jest nadawana według wzorca V*nazwa\_klasy\_komponentu\_gwt*. Ostatnim elementem, który jest najważniejszy w naszej zabawie jest klasa, która reprezentuje komponent po stronie serwera.

Listing 4. Klasa po stronie serwera

import java.util.Map;

import pl.koziolekweb.fb.test.gwt.client.ui.VMyComponentGWT;

import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.ui.AbstractComponent;

@com.vaadin.ui.ClientWidget(VMyComponentGWT.class)
public class MyComponentGWTProxy extends AbstractComponent {

	private static final long serialVersionUID = 1L;

	@Override
	public void changeVariables(Object source, Map<string object=""> variables) {
		super.changeVariables(source, variables);
	}

	@Override
	public void paintContent(PaintTarget target) throws PaintException {
		super.paintContent(target);
	}

}
</string>

Tu najważniejszą rzeczą jest adnotacja ClientWidget, która wskazuje na implementację Paintable z którą będziemy się komunikować. Reszta w tym przypadku nie jest potrzebna.

Podsumowanie części pierwszej

Jak widać stworzenie własnego komponentu jest proste. Jeżeli chcemy integrować komponent GWT bez interakcji to też nie jest to duży problem. W drugiej części poruszę problem komunikacji pomiędzy GWT, a Vaadin.