Index
Elsewhere
Navigation
« Adventures with Scala and Vaadin - Part 4 | Main | Adventures with Scala and Vaadin - Part 2 »
Tuesday
Jun302009

Adventures with Scala and Vaadin - Part 3

Some Vaadin at last.

Download Vaadin from here and unpack it. You only really need the minimal one jar download, but with documentation this well written it'd be a shame not to grab it all.

They have platform specific downloads because some pieces of the underlying GWT toolset use SWT. As far as I can tell, there's no runtime platform specificity and I'm not going to be touching the GWT tools in this series, so don't worry about it.

From the download copy the vaadin-6.0.0.jar file ( hidden inside the WebContent directory if you downloaded the full installation ) into your spike/lib directory.

SBT adds any jars it finds in the lib directory to the classpath. Old-school styling baby!

And now some code.

The first "why don't you follow along at home" example from the Book of Vaadin is on page 24.

You need to configure the Vaadin servlet in the web.xml file. Sorry, back to the XML grindstone.

Insert this into the web-app element:


<display-name>myproject</display-name>
<context-param>
<description>Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<servlet>
<servlet-name>Spike Application</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>spike.SpikeApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Spike Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>


The web.xml will now route all requests through the Spike Application servlet that's will look for the spike.Application class. I've changed the class and package name from the example to match the project and to keep package hierarchies short-ish.

The original Java code on the first example looks like this:


package com.example.myproject;

import com.vaadin.Application;
import com.vaadin.ui.*;

public class MyprojectApplication extends Application
{
@Override public void init() {
final Window mainWindow = new Window("Myproject Application");
Label label = new Label("Hello Vaadin user");
mainWindow.addComponent(label);
mainWindow.addComponent(
new Button("What is the time?",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
mainWindow.showNotification("The time is " + new Date());
}
}));
setMainWindow(mainWindow);
}
}


Not too bad. Particularly when you consider what it generates - a full page of HTML with a button with a server-side call back that displays the server time on screen in an area that fades out after a few seconds.

Not too bad, but I think Scala can do better. Stage 1 - Transliteration.

Create the application class:


~/code/spike : mkdir src/main/scala/spike
~/code/spike : touch src/main/scala/spike/Application.scala


Then edit the class so that it looks like so:


package spike

import com.vaadin.Application
import com.vaadin.ui._
import java.util.Date

class SpikeApplication extends Application {
override def init(): Unit = {
val mainWindow = new Window("Spike Application")
val label = new Label("Hello Spike Application User!")
mainWindow.addComponent(label)
mainWindow.addComponent(
new Button("What is the time?",
new Button.ClickListener() {
def buttonClick(event: Button#ClickEvent) {
mainWindow.showNotification("The time is " + new Date())
}}))
setMainWindow(mainWindow)
}
}


Start Jetty:

~/code/spike : sbt
>jetty-run

Then navigate to http://localhost:8080

Exciting - not so much. Still, the Scala here is pretty much identical to the Java code. It is nice to know that you can take a piece of Vaadin code and translate it without too much trouble. But if the Scala isn't any better - then Java would be a 'safer' choice.

Let's see if we can pimp this code.

Hmm, I don't like the inner class listener. In Java this is the best choice, in Scala we have more choices. Closures/Blocks/BlockClosures/Anonymous Functions/Lambdas/Anonymous Delegates/whatever you want to call them. to the rescue. We can create a button that takes a closure and never have to write one of those ugly little inner classes again.

Another thing that bothers me is that call to setMainWindow. Inheritance like this makes testing and TDD harder because I'm tied into the way the Application class works. I don't like that. That's not a game I'm going to play. I've an idea of how to extract us from that hole using abstract traits. But that can wait until I try writing tests.

After removing the inner class, slight blemishes in the rest of the code became more obvious so I've done a spot of in-lining and removed a few extraneous braces. I often find that once you can't see the little pimples until you've removed the massive warts. Anyway, the code now looks like this:


package spike

import com.vaadin.Application
import com.vaadin.ui._
import java.util.Date

class SButtonClickListener(action: Button#ClickEvent => Unit) extends Button.ClickListener {
def buttonClick(event: Button#ClickEvent): Unit = {
action(event)
}
}

class SButton(text: String, action: Button#ClickEvent => Unit) extends Button(text, new SButtonClickListener(action))

class SpikeApplication extends Application {
override def init: Unit = {
val mainWindow = new Window("Spike Application")
mainWindow.addComponent(new Label("Hello Spike Application User!"))
mainWindow.addComponent(
new SButton("What is the time?", _ => mainWindow.showNotification("The time is " + new Date)))
setMainWindow(mainWindow)
}
}


But, but, but, that's longer I hear you cry. Yes it is. But the first two classes can be pulled out and stored away somewhere and you're free of inner class event handlers for every button hence-forth.

The important part is the init method, isn't that much cleaner than before? You create a window, add a couple of components and pass it on.

For my money, this is a win.

Swap this code into place, execute a:

>jetty-restart

and take a look to make sure it hasn't changed.

Next time - continuous build and deploy and on to the next example.

References (2)

References allow you to track sources for this article, as well as articles that were written in response to this article.

Reader Comments (1)

Disclaimer: I work for IT Mill, the makers of Vaadin.

This really makes me want to take a better look at Scala, amazing stuff :)

About the inner class event handlers, though, one probably shouldn't use them for anything bigger than one-liners. For anything more complex it will be clearer to move the click listener logic to a separate method. This can be done like how you did by creating a new class that implements the ClickListener interface, or by letting the class handling the button implement it. I've found that the latter way is often clearer, because it keeps a component's logic near the component itself. Doing it that way results in (IMO) pretty clear code:

public class ClickListenerApp extends Application implements ClickListener {

private Window mainWindow;

@Override
public void init() {
setMainWindow(mainWindow = new Window("Myproject Application"));

mainWindow.addComponent(new Label("Hello Vaadin user"));
mainWindow.addComponent(new Button("What is the time?", this));
}

@Override
public void buttonClick(ClickEvent event) {
mainWindow.showNotification("The time is " + new Date());
}
}

I agree with you about the mandatory main window initialization stuff. I created a ticked about it (http://dev.vaadin.com/ticket/3108), lets see what our R&D team thinks about it.

July 1, 2009 | Unregistered CommenterHenri Muurimaa

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
All HTML will be escaped. Hyperlinks will be created for URLs automatically.