Server-side components provide the API for user applications to build their user interface. Many applications do not ever need to bother with the client-side implementation of the standard components, but those that use their own GWT widgets need to have corresponding server-side components.
If you are using the Vaadin Plugin for Eclipse, the wizard for creating new widgets will also create a stub of the server-side component for you. See Section 11.2.1, “Creating a Widget” for detailed instructions.
A server-side component has two basic tasks: it has to be able to serialize its state variables to the corresponding client-side component, and deserialize any user input received from the client. Many of these tasks are taken care of by the component framework.
A server-side component needs to be bound to a specific client-side
widget. This is done with a special annotation. For example, for the
ColorPicker
server-side component, we define:
import com.vaadin.demo.colorpicker.widgetset.client.ui.VColorPicker; @ClientWidget(VColorPicker.class) public class ColorPicker extends AbstractField { ...
The annotation is read during the compilation of the widget with the GWT
Compiler. The compiler invokes a WidgetMapGenerator
that reads the annotations from the compiled server-side component
classes. It is therefore necessary that the server-side components are
compiled before the client-side compilation, as noted in Section 11.8.4, “Compiling GWT Widget Sets”.
The serialization is broken down into server-client serialization and client-server deserialization in the following sections. We will also present the complete example of the server-side implementation of the Color Picker component below.
The server-side implementation of a component must be able to serialize
its data into a UIDL message that is sent to the client. You need to
override the paintContent()
method, defined in
AbstractComponent
. You should call the superclass
to allow it to paint its data as well.
The data is serialized with the variants of the
addAttribute()
and
addVariable()
methods for different basic data
types.
The UIDL API offered in PaintTarget
is covered in
Section A.1, “API for Painting Components”.
The server-side component must be able to receive state changes from the
client-side widget. This is done by overriding the
changeVariables()
method, defined in
AbstractComponent
. A component should always call
the superclass implementation in the beginning to allow it handle its
variables.
The variables are given as objects in the variables
map, with the same key with which they were serialized on the
client-side. The object type is likewise the same as given for the
particular variable in updateVariable()
in the
client-side.
@Override public void changeVariables(Object source, Map variables) { // Let superclass read any common variables. super.changeVariables(source, variables); // Sets the currently selected color if (variables.containsKey("colorname") && !isReadOnly()) { final String newValue = (String)variables.get("colorname"); // Changing the property of the component will // trigger a ValueChangeEvent setValue(newValue, true); } }
The above example handles variable changes for a field component
inheriting AbstractField
. Fields have their value
as the value property of the object. Setting the value with
setValue()
, as above, will trigger a
ValueChangeEvent
, which the user of the component
can catch with a ValueChangeListener
.
Contained components, such as components inside a layout, are deserialized by referencing them by their paintable identifier or PID.
The following example provides the complete server-side
ColorPicker
component for the Color Picker
example. It has only one state variable: the currently selected color,
which is stored as the property of the component. Implementation of the
Property
interface is provided in the
AbstractField
superclass of the component. The UIDL
tag name for the component is colorpicker
and the state
is communicated through the colorname
variable.
package com.vaadin.demo.colorpicker; import com.vaadin.demo.colorpicker.widgetset.client.ui.VColorPicker; ... /** * Color picker for selecting a color from a palette. * * @author magi */ @ClientWidget(VColorPicker.class) public class ColorPicker extends AbstractField { public ColorPicker() { super(); setValue(new String("white")); } /** The property value of the field is a String. */ @Override public Class<?> getType() { return String.class; } /** Set the currently selected color. */ public void setColor(String newcolor) { // Sets the color name as the property of the component. // Setting the property will automatically cause // repainting of the component with paintContent(). setValue(newcolor); } /** Retrieve the currently selected color. */ public String getColor() { return (String) getValue(); } /** Paint (serialize) the component for the client. */ @Override public void paintContent(PaintTarget target) throws PaintException { // Superclass writes any common attributes in the // paint target. super.paintContent(target); // Add the currently selected color as a variable in // the paint target. target.addVariable(this, "colorname", getColor()); } /** Deserialize changes received from the client. */ @Override public void changeVariables(Object source, Map variables) { // Sets the currently selected color if (variables.containsKey("colorname") && !isReadOnly()) { // Changing the property of the component will // trigger a ValueChangeEvent setValue((String) variables.get("colorname"), true); } } }