JAX London 2014: A retrospective
Client and server-side in harmony

Modern Web with Vaadin 7 and JavaScript

TapioAali
vaadin

Vaadin’s Tapio Aali shows us how to get the most out of the Java-friendly web framework, with a bit of jQuery and JavaScript thrown in.

In an article orginally published in the August edition of JAX Magazine, Vaadin’s Tapio Aali shows us how to get the most out of the Java-friendly web framework, with a bit of jQuery and JavaScript thrown in.

Vaadin is an open source Java-based framework for building modern web applications. The core idea of the framework is that all application logic is run in the server-side, while the client-side is only responsible for sending the user actions to the server and reacting to the responses it receives. Being based on GWT, both the client and the server code can be written in pure Java.

The latest major version, Vaadin 7, was released in February. The most prominent change from Vaadin 6 was the integration of GWT to Vaadin, which meant better support for client-side widget development and even gave the ability to create offline Vaadin applications.

While the server-side programming model was kept solid in Vaadin 7, it was made much more extensible. Other changes included the introduction of the new RPC and shared state system, redesigned form-to-data binding and the support for Sass (Syntactically Awesome Style Sheets). Another interesting new feature was the ability to use any kind of JavaScript widgets directly with Vaadin applications.

Vaadin 7.1 was released in June. It contained a bunch of new features including support for Atmosphere-based asynchronous server push and an integrated calendar component.  

Add-ons, components, widgets and extensions 

Before diving more deeply into the extension model of Vaadin, a few terms should probably be made clear. First, in the Vaadin world, an add-on can be about anything that helps in the development of Vaadin applications: UI components, toolkits, plugins that integrate Vaadin with different development tools, or application bases. Normally, these can be found from Vaadin Directory [1].

Since Vaadin is a UI library, a component either refers to something which display things to the user or something which handles his/her input. In order to create a component, at least a server-side class is required. If the component requires UI functionality that cannot be created using other existing components, a client-side widget is also needed. While the server-side part is written in Java—or any language that is supported by JVM—the client-side can be implemented using JavaScript, too.

Finally, there are the extensions. It’s a new concept introduced in Vaadin 7 that gives you the possibility to directly modify both the server and client-side functionality, allowing the alteration of the look and the behaviour of the existing components.

From the server to the client and back: component development in Vaadin 7

While the usage of pure Java and GWT has remained as the foundation of the widget development in Vaadin 7, there has been massive evolution under the hood. The basic idea has been to separate the code of the widgets into three parts: the server-side component, the client-side widget and the connector.

In Vaadin 6, the widget and the connector were the same thing. Therefore there were normally only two classes: the client-side widget and the server-side API for it. In addition to those, Vaadin 7 adds one extra required class: the connector that defines how the sides are connected to each other.

Naturally, in most cases, some kind of communication is required between the sides. Here is the biggest change: instead of the old way of sending attributes, variables and events between a paint target and an application connection, the communication is now done by using a state object and remote procedure calls.

The state is a class that defines the variables that the framework keeps in sync between the sides automatically, notifying the client if the state is modified in the server-side. When compared to the model used in Vaadin 6, this is a far more explicit way of data sharing, which is archived by adding one extra class.

While the state is always supposed to be in sync, remote procedure calls can be used to communicate stateless events, such as button clicks or other user interaction. Naturally, the RPCs can be initiated from the either side.

Probably the easiest way to explore how you can create a fully-fledged GWT-based Vaadin widget that uses both state and RPCs, is to create a project using the Maven archetype com.vaadin.vaadin-archetype-widget or with the Vaadin Plug-in for Eclipse by adding a new Vaadin Widget to an existing Vaadin 7 project.

Using a JavaScript-based widget with Vaadin 7

In Vaadin 6, the only way to use a JavaScript-based component was by creating a GWT wrapper for it and compiling it to the widgetset. This isn’t required anymore—with Vaadin 7, you can use any JavaScript component with little extra code.

As an example, I will create a component called LinkWithQTip that displays a thumbnail of a link when hovering over its text. It is based on a minimalistic jQuery plugin called LinkQTip [2].

It is often easiest to start the development of a new component by creating a state object which, as mentioned before, holds the variables that are shared and kept in sync between the server and the client.

In this example, I’ve reduced the variables to two that are most certainly required for a link: the URL that it points to and the link text. Because we’re creating a JavaScript-based component, the state object is based on special class: JavaScriptComponentState.

public class LinkWithQTipState extends JavaScriptComponentState {

public String url;

public String text;

}

The server-side component extends a class called AbstractJavaScriptComponent. First it loads the required JavaScript files: the jQuery library, the LinkQTip plugin and the connector that joins it to the server-side. The loading is done using @JavaScript class annotation.

The other parts of the server-side component don’t differ in any way from a Vaadin component whose client code is written in GWT. The server-side component provides an API that in this example consists of one function that allows the user to change the text of the link. See Listing 1.

Listing 1

@JavaScript({ "client/jquery-1.10.1.min.js",

"client/jquery.linkqtip.js",

"client/linkwithqtip_connector.js" })

public class LinkWithQTip extends AbstractJavaScriptComponent {

public LinkWithQTip(String url, String text) {

getState().url = url;

getState().text = text;

}

protected LinkWithQTipState getState() {

return (LinkWithQTipState) super.getState();

}

public void setText(String text) {

getState().text = text;

}

}

End

The client-side: connecting jQuery widget to Vaadin

When a JavaScript-based component is created, Vaadin searches for a JavaScript function whose name comes from the package and the server-side class of the component, replacing dots with underlines. This function is the connector that receives the parameters from the state object and applies them to the actual JavaScript widget. The initialization of the connector can be compared to the $(document).ready() function of jQuery since it is called when the required surroundings of the component are ready to be used.

The connector of LinkQTip is therefore a function called com_vaadin_linkwithqtip_LinkWithQTip. It creates an <a> element with the text and the url from the state object and applies the linkQTip plugin to it before appending the element to the DOM. It also applies a state change listener that changes the link text if it is modified on the server-side. See Listing 2.

Listing 2

com_vaadin_linkwithqtip_LinkWithQTip = function() {

var aElement = $('<a/>', {

href: this.getState().url

});

var linkQTip = aElement.linkQTip();

$(this.getElement()).append(aElement);

this.onStateChange = function () {

aElement.html(this.getState().text);

};

};

End

Stateless actions: Adding RPCs

Like all other components, JavaScript-based widgets can also perform RPC in both directions. Naturally the ‘classical’ solution based on defining interfaces can also be used, but with JS connectors, there is also a simplified mechanism available.

Let’s say we want to be able to toggle the link preview from the server-side. This is clearly a stateless action since the server doesn’t know if the preview is visible or not; it just tells the client-side to show the preview if it is hidden and vice versa.

The first thing we need to do is add a function called toggle() to the connector. It redirects the call to the actual plugin.

this.toggle = function() {

aElement.data('LinkQTip').toggle();

};

In order to do an RPC call from the server-side, AbstractJavaScriptComponent.callFunction() is used. Therefore we add a new API method that uses it to call the toggle() function of the connector.

public void toggleQTip() {

callFunction("toggle");

}

Another nice feature we could have is the ability to know on the server-side when a link preview is actually opened. The jQuery plugin has a function called onLinkQTipShow that is set in the initialization phase. Let’s make it call a new function onLinkQTipOpened() of the connector.

var self = this;

var linkQTip = aElement.linkQTip({

onLinkQTipShow: self.onLinkQTipOpened

});

The actual implementation for the function is given on the server-side, in the constructor of LinkWithQTip, as shown in Listing 3.

Listing 3

addFunction("onLinkQTipOpened", new JavaScriptFunction() {

@Override

public void call(JSONArray arguments) throws JSONException {

for (LinkQTipOpenedListener listener : listeners) {

listener.qTipOpened();

}

}

});

In order to notify the users of the component, a listener interface is used.

public interface LinkQTipOpenedListener extends Serializable {

public void qTipOpened();

}

Naturally also an API function for adding new listeners is required.

public void addQTipOpenedListener(LinkQTipOpenedListener listener) {

listeners.add(listener);

}

That’s really all the code that is required to use a JavaScript plugin with two-way RPC with Vaadin. All that is left to do is apply the relevant styles so that the hovering thumbnail is displayed correctly. Vaadin 7 introduced a new annotation, @StyleSheet, that can be used to load CSS (or SCSS) files from the WebContent/VAADIN folder. Therefore if the jquery.linkqtip-styles.css file is copied there, it can be loaded by adding one line to the LinkWithQTip class.

@StyleSheet("vaadin://jquery.linkqtip-styles.css")

Now the add-on is ready to be added to the Vaadin Directory. Since anyone is allowed to upload new add-ons, all you need to do is to export the jar using either Maven or Vaadin Plug-in for Eclipse. Then you can browse to the Authoring page, fill in the required details and finally release your add-on for everyone [3].

Some final words

With this approach, the huge amount of already existing jQuery-based plugins or any other JavaScript libraries can be used with Vaadin applications really easily. Also, since no conversion from Java to JavaScript is needed, the code can be modified and deployed live without need for widgetset compilation.

Naturally, this has also some drawbacks. Trying to refer to any GWT code from JavaScript is practically impossible. Also, since GWT is no longer taking care of browser differences, it’s up to the user or the used library to handle them.

Both the jQuery plugin and the Vaadin project are Apache licensed and available in GitHub [2] [4]. You can find demos of these projects via at my personal blog [5] [6].

Example projects

  • https://vaadin.com/addon/webcam

  • https://vaadin.com/addon/dcharts-widget

  • https://vaadin.com/addon/ckeditor-wrapper-for-vaadin

  • https://vaadin.com/addon/aceeditor

  • https://vaadin.com/addon/googleanalyticstracker

References

[1] https://vaadin.com/directory

[2] https://github.com/tjkaal/LinkQTip

[3] https://vaadin.com/directory#authoring

[4] https://github.com/tjkaal/LinkWithQtip).

[5] http://tapio.virtuallypreinstalled.com/jquery.linkqtip/jquery.linkqtip-example.html

[6] http://tapio.virtuallypreinstalled.com/LinkQTip/.

 

 


Author
Comments
comments powered by Disqus