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!