Archive for the ‘Wicket’ Category

Wicket 10: Form binding with a value object

30 October 2008

This is part 10 of a series about Wicket.

We need to collect user input about persons. This input will be passed to another page, so we’ll build two of them: Input that accepts user input and Output that displays the result.

Each person has a name and an age.

public class Person implements Serializable {
   private String name;
   private Integer age;

   // getters and setters
}

Output

Output.html simply displays the values of a Person.

  Hello <span wicket:id="name"></span>, you are <span wicket:id="age"></span> years old!

Output.java receives a Person,

public Output(Person person) {
}

and makes its values available to the markup.

public Output(Person person) {
   add(new Label("name", person.getName()));
   add(new Label("age", String.valueOf(person.getAge())));
}

Input

Input.html has a form. The trick is to use the exact name of the fields in the HTML form.

<form wicket:id="form">
  Name <input type="text" wicket:id="name" /><br />
  Age <input type="text" wicket:id="age" /><br />
  <input type="submit" value="OK" />
</form>

So the form has the same fields with the same name as the value object.

Input.java has the same form,

Form form = new Form("form") {
   protected void onSubmit() {
      // redirect to the Output page
   }
};

that should redirect to the Output page

Person person = new Person();
Form form = new Form("form") {
   protected void onSubmit() {
      setResponsePage(new Output(person));
   }
};

and should automatically bind user input to the value object.

Person person = new Person();
Form form = new Form("form", new CompoundPropertyModel(person)) {
   protected void onSubmit() {
      setResponsePage(new Output(person));
   }
};

Complete code

Input.html

<html>
  <body>
    <form wicket:id="form">
      <table>
        <tr><td>Name</td><td><input type="text" wicket:id="name" /></td></tr>
        <tr><td>Age</td><td><input type="text" wicket:id="age" /></td></tr>
        <tr><td colspan="2"><input type="submit" value="OK" /></td></tr>
      </table>
    </form>
  </body>
</html>

Input.java

public class Input extends WebPage {
   private Person person = new Person();
   public Input() {
      final Form form = new Form("form", new CompoundPropertyModel(person)) {
         protected void onSubmit() {
            setResponsePage(new Output(person));
         }
      };
      final TextField name = new TextField("name");
      final TextField age = new TextField("age");
      form.add(name);
      form.add(age);
      add(form);
   }
}

Output.html

<html>
  <body>
    Hello <span style="color:coral" wicket:id="name"></span>,
    you are <span wicket:id="age"></span> years old!
  </body>
</html>

Output.java

public class Output extends WebPage {
   public Output(Person person) {
      add(new Label("name", person.getName()));
      add(new Label("age", String.valueOf(person.getAge())));
   }
}

Result

Let’s type something,

The user enters some data

The user enters some data

and submit.

The result

The result

Review

  • A Serializable value object is passed between two pages.
  • The value object is automatically filled with the values of the form using a CompoundPropertyModel.
  • The value object is bound to the form.

Here’s an elegant alternative coding style.

   IModel<Person> model = new CompoundPropertyModel<Person>(new Person());
   final Form form = new Form("form", model) {
      protected void onSubmit() {
         setResponsePage(new Output(model.getObject()));
      }
   };

Wicket 9: Setup a form

29 October 2008

This is part 9 of a series about Wicket.

We simply want to pass the value of a text field to another page, so we’ll build two pages: Input that accepts user input and Output that displays the result.

Input.html

Consider this simple form. It consists of a text field and a submit button.

<form>
  <input type="text" /><input type="submit" value="OK" />
</form>

Let’s add wicket ids.

<form wicket:id="form">
  <input type="text" wicket:id="name" /><input type="submit" value="OK" />
</form>

Output.html

Output.html simply says hello to whatever is the value of the <span>.

Hello <span></span> !!

Let’s give it a wicket id.

Hello <span wicket:id="output"></span> !!

Output.java

There is a single element in the HTML markup that needs a value.

add(new Label("output", new Model()));

So we can pass it through the constructor.

public Output(Model model) {
   add(new Label("output", model));
}

Input.java

Here’s the form and the field.

final Form form = new Form("form");
final TextField field = new TextField("name");

The form contains the field and the page contains the form.

form.add(field);
add(form);

We’d like to specify the behavior of the form when it is submitted.

final Form form = new Form("form") {
   protected void onSubmit() {
   }
};

Actually, the request should be received by an Output page.

final Form form = new Form("form") {
   protected void onSubmit() {
      setResponsePage(new Output(null));
   }
};

The trick is to send the model of the field to the constructor of that page.

private Model model = new Model();
public Input() {
   final Form form = new Form("form") {
      protected void onSubmit() {
         setResponsePage(new Output(model));
      }
   };
   final TextField field = new TextField("name", model);
   form.add(field);
   add(form);
}

Complete code

Input.html

<html>
  <body>
    <form wicket:id="form">
      Please enter your name :
      <input type="text" wicket:id="name" /><input type="submit" value="OK" />
    </form>
  </body>
</html>

Input.java

public class Input extends WebPage {
   private Model model = new Model();
   public Input() {
      final Form form = new Form("form") {
         protected void onSubmit() {
            setResponsePage(new Output(model));
         }
      };
      final TextField field = new TextField("name", model);
      form.add(field);
      add(form);
   }
}

Output.html

<html>
  <body>
    Hello <span wicket:id="output" style="font-size:x-large;"></span> !!
  </body>
</html>

Output.java

public class Output extends WebPage {
   public Output(Model model) {
      add(new Label("output", model));
   }
}

Result

A simple form

A simple form

Let’s type something,

The user enters data

The user enters data

and submit.

The result

The result

Review

  • To specify the behavior of a Form during submission, just implement its onSubmit() method.
  • You may pass anything that IS-A Serializable between two pages.

Wicket: Full guide for JDeveloper 11g

27 October 2008

This article presents how a complete Wicket project is built from ground-up in JDeveloper 11g.

Go through steps 1-3 to setup a wicket project.

Go through step 4 to create a page.

Go through steps 5-7 to deploy, test and debug the page.

1. Create a web project

File → New… → General → Projects → Web Project → OK.

Creating a new web project in JDeveloper

Creating a new web project in JDeveloper

In the wizard click next, give the project a name, e.g. WicketFun and click Next until the option Finish appears. The project should now appear in the Projects tab.

Project tab of JDeveloper

Project tab of JDeveloper

2. Concentrate all jars

Download wicket from wicket.apache.org → Releases → Wicket 1.4 → Select an appropriate mirror and get apache-wicket-1.4-m3.zip

Download simple logging facade from slf4j.org → Download → slf4j-1.5.2.zip

Create a folder and place inside the following:

  • apache-wicket-1.4-m3\lib\wicket-1.4-m3.jar
  • slf4j-1.5.2\slf4j-simple-1.5.2.jar
  • slf4j-1.5.2\slf4j-api-1.5.2.jar

Add these jars to the classpath by right clicking on the project → Project Properties… → Libraries and Classpath → Add JAR/Directory…

These three are all you need for a wicket application. However, there are some extra interfaces of great interest: The date-time functionality (wicket-datetime-1.4-m2.jar) and the integration with Spring (wicket-spring-1.4-m2.jar).

3. Make the WebApplication

Wicket’s starting point is a WebApplication.

Right click on project → New → General → Simple Files → Java Class → Provide the name MyApplication, declare that it extends WebApplication and click OK.

Create a new class in JDeveloper

Create a new class in JDeveloper

This class should implement the getHomePage() method.

package wicketfun;

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

public class MyApplication extends WebApplication {

    public Class<? extends Page> getHomePage() {
        return null;
    }

}

For the time being just let it return null.

Accessing web.xml through the Projects tab

Accessing web.xml through the Projects tab

In the Projects tab double-click on web.xml → XML and paste the following elements

<filter>
   <filter-name>WicketApplication</filter-name>
   <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
   <init-param>
      <param-name>applicationClassName</param-name>
      <param-value>wicketfun.MyApplication</param-value>
   </init-param>
</filter>
<filter-mapping>
   <filter-name>WicketApplication</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

Here’s how web.xml should look.

DD in the XML editor of JDeveloper

DD in the XML editor of JDeveloper

4. Make a page

Let’s call it Hello. We should create Hello.html and Hello.java! As simple as it gets.

Right click on project → New → General → Simple Files → Java Class → Provide the name Hello, the package pages, make it extend WebPage and click OK.

This class should provide a default no-arg constructor.

package pages;

import org.apache.wicket.markup.html.WebPage;

public class Hello extends WebPage {

    public Hello() {
        // wicket action here
    }

}

To make the classes compile right click the project and select Rebuild.

After a successful compilation, right click on project → New… → Web Tier → HTML → HTML Page → Provide the name Hello and click on Browse….

Creating an HTML file in JDeveloper

Creating an HTML file in JDeveloper

Expand the classes folder and double-click on pages.

Bundling the HTML page together with the class file

Bundling the HTML page together with the class file

In this way the html file will be bundled in the same directory with the class file. Just press OK to complete.

Let’s make this page simply display the current year.

<html>
  <body>
      The year is: <span wicket:id="year"></span>
  </body>
</html>

Back to the class for some action.

package pages;

import java.util.Calendar;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;

public class Hello extends WebPage {

    public Hello() {
        Integer year = Calendar.getInstance().get(Calendar.YEAR);
        add(new Label("year", year.toString()));
    }

}

5. Declare the home page

Every time you create a page you’d like to test it.

Just go to the getHomePage() of your WebApplication and make it return your page.

package wicketfun;

import pages.Hello;
import org.apache.wicket.Page;
import org.apache.wicket.protocol.http.WebApplication;

public class MyApplication extends WebApplication {

    public Class<? extends Page> getHomePage() {
        return Hello.class;
    }

}

In this way when the application context is called on the browser, e.g. http://localhost:8080/wicket, this page will be called.

6. Run the page

Deploy the application to your favorite server, for example JBoss, GlassFish or the bundled Weblogic, to see it in action.

7. Debug the page

Wicket keeps the java code totally independent from the HTML markup. So debugging is easy.

Make a breakpoint by clicking on the left of the desired line.

Debugging a wicket page is trivial

Debugging a wicket page is trivial

References

Wicket 8: Comfortable instance variables

12 September 2008

This is part 8 of a series about Wicket.

In JSP/Servlets you should not use instance variables; in Wicket it’s a comfort.

Let’s consider this servlet.

public class Servlet1 extends HttpServlet {
   private Integer number = 0;
   public void doGet(HttpServletRequest request,
      HttpServletResponse response)
      throws ServletException, IOException {
      number = number + 1;
      response.getWriter().
      println("Instance variable: " + number);
   }
}

If you open two different browsers and hit the refresh button several times, you’ll see that the number is incremented with every request. This happens because a servlet gets initialized once and serves the various requests with different threads.

Let’s see this servlet as well:

public class Servlet1 extends HttpServlet {
   private Integer number = new Random().nextInt();
   public void doGet(HttpServletRequest request,
      HttpServletResponse response)
      throws ServletException, IOException {
      response.getWriter().
      println("Instance variable: " + number);
   }
}

Similarly, in this second servlet the number shown is always the same as if the state was static and final.

Fortunately in Wicket every WebPage is a plain Java object.

For example consider Page.html

<html>
   <body>
      <h3 wicket:id="number"></h3>
   </body>
</html>
</pre>

and Page.java

public class Page extends WebPage {
   private Integer number = 0;
   public Page() {
      number = number + 1;
      add(new Label("number", "Instance variable: " + number));
   }
}

The result is what we really expect. How about this.

public class Page extends WebPage {
   private Integer number = new Random().nextInt();
   public Page() {
      add(new Label("number", "Instance variable: " + number));
   }
}

Just deploy it and hit refresh a few times: A new number is shown every time!

Review

Instance variables of a web page are a great convenience, in contrast to what happens with a servlet.

WebPage objects are plain Java objects.

Wicket 7: Two elements with the same value

6 September 2008

This is part 7 of a series about Wicket.

Let’s type something in a field, press submit and see what was typed in the same page.

Consider SamePage.html. First we need an input field to type in, accompanied with a submit button, surrounded by a form of course.

<form>
   <input type="text"/><input type="submit" value="OK"/>
</form>

We also need a span to display what we have just typed.

<form>
   <input type="text"/><input type="submit" value="OK"/>
</form>
<span style="color:coral"></span>

Let’s add wicket ids to <form>, <input> and <span>.

<form wicket:id="form">
   <input type="text" wicket:id="input"/><input type="submit" value="OK"/>
</form>
<span style="color:coral" wicket:id="output"></span>

So the form has id “form”, the input field “input” and the span “output”.

Here’s the complete SamePage.html

<html>
   <body>
      <form wicket:id="form">
         <input type="text" wicket:id="input"/><input type="submit" value="OK"/>
      </form>
      <span style="color:coral" wicket:id="output"></span>
   </body>
</html>

Now let’s build the associated Java class that IS-A WebPage. All the action happens in its constructor.

Here’s the form with id “form”.

final Form form = new Form("form");

Here’s the text field with id “input”.

final TextField input = new TextField("input");

And that’s the span (label) with id “output”.

final Label label = new Label("output");

Now, we follow the html markup: The form contains the input.

form.add(input);

The page contains the form,

add(form);

and the label.

add(label);

Now, to make input and label have the same value we simply provide a common Model.

final Model model = new Model();
final TextField input = new TextField("input", model);
final Label label = new Label("output", model);

This is the complete code of SamePage.java

public class SamePage extends WebPage {
   public SamePage() {
      final Model model = new Model();
      final Form form = new Form("form");
      final TextField input = new TextField("input", model);
      final Label label = new Label("output", model);
      form.add(input);
      add(form);
      add(label);
   }
}

Of course you may shorten the code by half with chaining, but this does not help debugging and maintenance.

public class SamePage extends WebPage {
   public SamePage() {
      final Model model = new Model();
      add(new Form("form").add(new TextField("input", model)));
      add(new Label("output", model));
   }
}

Let’s type something and submit.

A simple form

A simple form

The page refreshes as expected.

The span below the field repeats its value.

The span below the field repeats its value.

Review

  • Just provide the same Model to components that should have the same value.
  • You may take a look at TextField, Label and Form.