Seamless Wicket: Orchestrating your application

Posted by    |      

This is the second part in my short series on using Wicket with Seam.

In the first part we looked at how to create a project. Here, we'll get to the meat of how you can use Seam Security, conversations and bijection and more of Seam's goodies with Wicket. One of the primary goals of Seam is to allow you to use one kind of stuff when writing your project, so when integrating with Wicket with Seam we've tried, as far as possible, to allow you to use exactly the same annotations, with exactly the same meaning in your Wicket application.

Of course, some annotations and their results don't make sense when using Wicket, and some annotations just aren't supported yet - if you see an annotation you would like supported in Wicket, please let us know.

Security

First, let's look at using Seam Security with Wicket. Both @Restrict and @RoleCheck are supported. You can read more about the use of these annotations and their attributes in the Seam Security chapter; but briefly

  • Applying @Restrict("#{identity.loggedIn}") to a Wicket component will require the user to be logged in to access that component. You can define the annotation on a page class to restrict access to the entire page, or on just a sub-component to restrict access to that sub component.

For example, here the user must be logged in to access the home page:

@Restrict("#{identity.loggedIn}")
public class HomePage extends WebPage {
  • Annotating a page or component with an annotation which has the @RoleCheck meta-annotation

For example, here only administrators can access the admin page:

@RoleCheck
@Target(TYPE)
@Retention(RUNTIME)
public @interface Admin {}
@Admin
public class AdminPage extends WebPage {

Finally, you can set the login page through your Application:

public class WicketBookingApplication extends SeamWebApplication {

   protected Class getLoginPage() {
      return Home.class;
   }

Conversations and Validation

Just as you can use @Begin and @End in a Seam component to start and end a conversation, you can do the same in your Wicket component. For example, to start a long running conversation as we click on the link to create a new user. We can even enable manual flush mode to start an atomic conversation:

public class HomePage extends WebPage {

   public HomePage(PageParameters parameters) {
      add(new Link("createUser") {

         @Begin(flushMode=MANUAL)
         public void onClick() {
            setResponsePage(com.mydomain.wicket_tutorial.web.CreateUser.class);
         }
      });
   }

The User entity probably has some Hibernate Validator constraints which we want to apply. Seam provides a Wicket validator, org.jboss.seam.wicket.ModelValidator which will apply the constraints to the Wicket input component:

public class CreateUser extends WebPage {

   @In UserManager userManager;
   
   public CreateUser(PageParameters parameters) {
      super(parameters);
      add(new CreateUserForm("userForm"));
   }

   public class CreateUserForm extends Form {
      
      public CreateUserForm(String id) {
         super(id);
         // Add a field label
         add(new Label("usernameLabel", "Username:"));

         TextField username = new TextField("username");

         // Attach the field to the Entity
         username.setModel(new PropertyModel(userManager.getUser(), "username"));

         // Attach the Seam model based validator
         username.addValidator(new ModelValidator(User.class, "username"));
         add(username);

         // Give feedback to the user if there is an error
         add(new FeedbackPanel("message", new ContainerFeedbackMessageFilter(username)));
      }

Of course, you can easily wrap this behaviour up in a Wicket border (take a look at FormInputBorder.java and FormInputBorder.html in the Wicket example).

Finally, we want to end the conversation when the user submits the form:

     @End 
      protected void onSubmit() {
         userManager.createUser();
      }
   }
}

You could even start a conversation on a regular Seam component, and end it in Wicket!

Sometimes, you might want to ensure that a Wicket page can only be accessed inside a long running conversation; you can do this using the @NoConversationPage annotation:

@NoConversationPage(HomePage.class)
public class CreateUser extends WebPage {

Bijection

In part 1 we showed some basic injection, and it really doesn't get any harder! Let's say the User entity was a Seam component as well, we could just biject it into the Wicket component:

public class CreateUser extends WebPage {

   // You can even use the Seam logger!
   @Logger static Log log;

   @In UserManager userManager;
   @In @Out User user;

And more!

Seam's event bus is a simple way to write a very loosely coupled application. You might want to use events from Wicket; of course, you can raise an event programatically:

     @End 
      protected void onSubmit() {
         userManager.createUser();
         Events.instance.raiseEvent("userCreated");
      }
   }
}

But you might want to do it declaratively:

     @End
      @RaiseEvent("userCreated")
      protected void onSubmit() {
         userManager.createUser();
      }
   }
}

And finally, Seam provides a simple way to add messages to display to the user in the business layer:

@Name("userManager")
public class UserManager {

   @In EntityManager entityManager;
   @In StatusMessages statusMessages;

   User user = new User();

   public User getUser() {
      return user;
   }

   public void createUser() {
      entityManager.persist(user);
      statusMessages.add("User " + user.getName() + " created!");
   }
}

So, armed with this toolkit, you should be able to create powerful Wicket applications with Seam!


Back to top