Quickstart: Create a Wicket Web Application with Scala

Scala is an object-functional programming language, designed to concisely express solutions in an elegant, type-safe and lightweight manner (from Wikipedia). Scala is making life easier and more productive for the Java developers.

Apache Wicket is a lightweight component-based web application framework for the Java programming language. It lets developer to omit heaps of XML configuration files and be concentrated on producing nice Java code.

I’d like to join these two perfect things together: to develop a Web application on excellent Web framework using elegant object-functional programming language!


Requirements

All necessary Wicket & Scala stuff is downloaded via Maven from the repositories upon request.

Check it up:

$ java –version
$ javac –version
$ scala -version
$ mvn -version


Start with a plain Wicket project

The best way to get started with Wicket project is to use Wicket Quickstart. It is made from Maven archetype:

$ mvn archetype:generate -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=6.8.0 -DgroupId=com.r.scalademo.wicket -DartifactId=scalawicket -DarchetypeRepository=https://repository.apache.org/ -DinteractiveMode=false

We have created a ready-to-use wicket application with a dummy web page HomePage.java and plain application class WicketApplication.java. We are going to code these classes in Scala. But let run it first:

$ mvn clean package jetty:run

Go to http://localhost:8080 to see that it just works.

Also you can import the project into your favorite IDE now. More information about IDE usage is available on Wicket Quickstart page.


Add Scala to Wicket project

Let’s add Scala support to our wicket project. I do not want to corrupt existing Java classes, so the project must be a mixed Java + Scala one!

Add support of Scala language as well as Scala testing tools into the project as maven dependencies. Do the following changes in pom.xml file:

   …

    <properties>

        …

        <scala.version>2.10.2</scala.version>
    </properties>
   <dependencies>

        …

        <!-- Scala  -->
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>

        <!-- scala test Test -->
        <dependency>
            <groupId>org.scala-tools.testing</groupId>
            <artifactId>specs_2.10</artifactId>
            <version>1.6.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.scalatest</groupId>
            <artifactId>scalatest</artifactId>
            <version>1.2</version>
            <scope>test</scope>
        </dependency>

        …
…

We’ve got Scala language support, but we cannot compile Scala classes yet. Add Scala plug-in into our project POM:

   …

   <plugins>

            …

            <plugin>
                <groupId>org.scala-tools</groupId>
                <artifactId>maven-scala-plugin</artifactId>
                <version>2.15.0</version>
                <executions>
                    <execution>
                        <id>scala-compile</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>scala-test-compile</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        …
…

This Scala-tools plug-in is triggered on process resources phase to compile Scala classes. By adding sources, all *.scala files from ./src/main/scala directory are detected as source code files. Then these files are compiled into Java byte code.

As you can see, Scala code is compiled not on “compile” phase but on preceding “process resources” phase. Therefore Scala classes are compiled before Java classes, and on Java compilation all classes developed in Scala are already in class path, i.e. visible for Java.

I always follow Wicket style and locate Wicket component resources together with the classes in the same directory. So, we need corresponding resource configuration in pom.xml:

    …
	
    <build>
        <resources>

            …

            <resource>
                <filtering>false</filtering>
                <directory>src/main/scala</directory>
                <includes>
                    <include>**</include>
                </includes>
                <excludes>
                    <exclude>**/*.scala</exclude>
                </excludes>
            </resource>

That’s it. We can develop Wicket components in Scala now!


Develop Wicket web page in Scala

For a new Wicket web page we need a HTML template. I create a new file:
./src/main/scala/com/r/scalademo/wicket/MyPage.html

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
    <p><span wicket:id="helloWorldLabel"/></p>
    <p><span wicket:id="helloPanel"/></p>
</body>
</html> 

And a file with text respurces:
./src/main/scala/com/r/scalademo/wicket/MyPage.properties

helloWorldLabel=Hello Scala!

And a component Scala class:
./src/test/scala/com/r/scalademo/wicket/MyPageTest.scala

package com.r.scalademo.wicket

import org.apache.wicket.markup.html.WebPage
import org.apache.wicket.request.mapper.parameter.PageParameters
import org.apache.wicket.markup.html.basic.Label
import org.apache.wicket.model.ResourceModel

class MyPage(parameters :PageParameters) extends WebPage{
  def helloLabelModel = new ResourceModel("helloWorldLabel")
  def helloLabel = new Label("helloWorldLabel", helloLabelModel)
  add(helloLabel)
}

I use one of the WebPage superclass constructors, the one with page parameters, as a “main” constructor of Scala class. The label and its model are declared in function programming way, as functions!

Of course I test the component with Wicket tester that is triggered as JUnit unit test:

package com.r.scalademo.wicket

import org.junit.Test
import org.apache.wicket.util.tester.WicketTester

@Test
class MyPageTest {

  @Test
  def testRender = {
    val tester = new WicketTester( new WicketApplication)
    tester.startPage(classOf[MyPage])
    tester.assertRenderedPage(classOf[MyPage])
    tester.assertVisible("helloWorldLabel")
  }

}

Set our Scala Wicket page as a home page of the application. As I’ve mentioned above, we have mixed Java + Scala project. So we keep existing Wicket application Java class, just change a value returned by getHomePage() method:

       @Override
       public Class<? extends WebPage> getHomePage()
       {
               return MyPage.class;
       }


That’s it. Now run the application:

$ mvn clean package jetty:run

… and enjoy our Wicket page developed in Scala on http://localhost:8080 :

scalawicket-demo-hello-scala


Wicket Ajax component in Scala

Let’s develop mentioned above Wicket application class in Scala. We do not need special application features now; it will be a tiny Scala class that declares a home page only:
./src/main/scala/com/r/scalademo/wicket/WicketScalaApplication.scala

package com.r.scalademo.wicket

import org.apache.wicket.protocol.http.WebApplication

class WicketScalaApplication extends WebApplication {

  override def getHomePage = classOf[MyPage]
}

It must be referred by the Wicket servlet filter in web.xml:

               <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
               <init-param>
                       <param-name>applicationClassName</param-name>
                       <param-value>com.r.scalademo.wicket.WicketScalaApplication</param-value>
               </init-param>
       </filter>

Also I want to develop a funny panel that dynamically generates “Hello world!” message using Ajax. It is done using the following HTML template:
/src/main/scala/com/r/scalademo/wicket/MyHelloPanel.html

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns=http://www.w3.org/1999/xhtml xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
<body>
<wicket:panel>
    <p><wicket:message key="nameLabel"/></p>
    <p><input wicket:id="inputField"/></p>
    <p><span wicket:id="helloLabel"/></p>
</wicket:panel>
</body>
</html>
 

Template consists of input field and “hello” label. By typing something to input field, the message on the label is updated with Ajax.

package com.r.scalademo.wicket

import org.apache.wicket.markup.html.panel.Panel
import org.apache.wicket.model.{Model, IModel}
import org.apache.wicket.markup.html.form.TextField
import org.apache.wicket.markup.html.basic.Label
import org.apache.wicket.ajax.AjaxRequestTarget
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior

class MyHelloPanel(id: String, model: IModel[_]) extends Panel(id, model) {

  // One more constructor
  def this(id: String) = this(id, new Model)

  // Input filed
  val inputField = new TextField[String]("inputField", Model.of(""))
  add(inputField)

  // Hello label
  val labelModel = new Model[String]
  val label = new Label("helloLabel", labelModel)
  label.setOutputMarkupId(true)
  add(label)

  // Doing update on the fly with ajax
  val ajaxBehavior = new OnChangeAjaxBehavior {
    def onUpdate(target: AjaxRequestTarget) {
      // Ugly implementation. StringResourceModel must be used instead.
      labelModel.setObject("Hello " + inputField.getInput + "!")
      target.add(label)
    }
  }
  inputField.add(ajaxBehavior)
}

The label and input field are instantiated in usual way and added to the page. The input field also got an “OnChange” Ajax behavior that fires upon the field is filled in. Ajax behavior updates the label with message generated using field content.

Run the application:

$ mvn clean package jetty:run

… the label is generated as you type your name http://localhost:8080 :

scalawicket-demo-ajax-component


Source code and working instance

Try this demo application. An instance is deployed to Google App Engine.

Source code on GitHub

Share