Wednesday, May 26, 2010

Wicket and Guice integration: an alternate route...

This post details a slightly different way of integrating Apache Wicket and Google Guice.

Many posts, reference docs and demos I've seen on the Internet so far, do not employ one of my most favorite features in Guice: the ServletModule to configure Wicket's filter. I really like this feature because I really don't like configuration files and the Web Descriptor (a.k.a web.xml) file is one of the most disliked of them all :) but Thanks to Guice this file's annoyance goes almost unnoticed.

So just to make it clear, the purpose of this integration is to bypass wicket's filter configuration in web.xml and put it in code instead.

Before we start here are several links to posts and reference docs about Wicket and Guice integration that are more common (but do use web.xml to config wicket):

Wicket Guice GuiceWebApplicationFactory javadoc
Alastair Maw’s blog - Wicket gets guicy
Wicket examples - Guice
Atomic Gamer dev blog - Wicket, Guice and Warp-Persist

We start with the web.xml file:
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">

 <filter>
  <filter-name>guiceFilter</filter-name>
  <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
 </filter>

 <filter-mapping>
  <filter-name>guiceFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

 <listener>
  <listener-class>com.codeark.wicketguicealt.Bootstrap</listener-class>
 </listener> 
</web-app>
This web.xml only configures Guice filter and a GuiceServletContextListener as per the instructions here.

The Bootstrap class loads our modules:
public final class Bootstrap extends GuiceServletContextListener { 
 @Override
 protected Injector getInjector() {  
  return Guice.createInjector(new MyModule(), new WebModule());
 } 
}
The binding and configuration of Wicket happens in WebModule (a subclass of ServletModule):
public class WebModule extends ServletModule {
 
 @Override
 protected void configureServlets() {
  bind(WebApplication.class).toProvider(WicketGuiceAppProvider.class);
  
  // avoids "Error initializing WicketFilter - you have no <filter-mapping> element..." 
  // IllegalArgumentException
  Map<String, String> params = new HashMap<String, String>();  
  params.put(WicketFilter.FILTER_MAPPING_PARAM, "/*");
  
  filter("/*").through(WicketGuiceFilter.class, params);
 }
} 
In the first line of configureServlets() we bind WebApplication to a provider, this provider will be our real application factory and will do all the work instead of GuiceWebApplicationFactory.

The GuiceWebApplicationFactory implementation requires that the injector will be stashed in the Servlet Context or that modules will be listed in the web.xml in an init-param like this:
<init-param>
        <param-name>module</param-name>
        <param-value>com.company.MyModule,com.company.MyOtherModule</param-value>
</init-param>
I think both options contradicts the real notion of Guice: "Rather than using an external XML file for configuration, Guice modules are written using regular Java code. Java is familiar, works with your IDE, and survives refactoring" and therefor I opted not to use GuiceWebApplicationFactory. Here is the provider we will use:
public class WicketGuiceAppProvider implements Provider<WebApplication> {
 
 private final Injector injector;

 @Inject
 public WicketGuiceAppProvider(Injector injector) {
  this.injector = injector;  
 }
 
 @Override
 public WebApplication get() {
  WicketGuiceApp app = new WicketGuiceApp(injector);  
  return app;
 }
}
It would be awesome if we could call addComponentInstantiationListener(new GuiceComponentInjector(app, injector)) here instead of passing the injector in the constructor (on injecting it) but GuiceComponentInjector uses InjectorHolder in its constructor:
public GuiceComponentInjector(Application app, Injector injector)
{
 app.setMetaData(GuiceInjectorHolder.INJECTOR_KEY, new GuiceInjectorHolder(injector));
 InjectorHolder.setInjector(this);
}
and InjectorHolder has a dependency on the application instance being tied to the current thread (Application.get() uses ThreadLocal):
public static void setInjector(ConfigurableInjector newInjector)
{
 Application application = Application.get();
 application.setMetaData(INJECTOR_KEY, newInjector);
}
Consequently, we can only call addComponentInstantiationListener() after Application.set() is called and the best place to do so is in the init() method of our WebApplication implementation. we could use Application.set() ourselves (tried that and it works fine) but the scary warnings in the javadoc are scary :-), so here is our WicketGuiceApp class with its init() method:
public class WicketGuiceApp extends WebApplication {
 
 private transient Injector injector;
 
 public WicketGuiceApp(Injector injector) {
  this.injector = injector;  
 }
 
 @Override
 protected void init() {  
  addComponentInstantiationListener(new GuiceComponentInjector(this, injector));
 }

 @Override
 public Class<? extends Page> getHomePage() {
  return HomePage.class;
 }
}
Please note that I've marked the Injector as transient. Under the hood, GuiceComponentInjector will handle the Injector's reference serialization and deserialization.

Back to WebModule, the second important thing we do in configureServlets() is to configure the Wicket filter and filter mapping. We are using our own WicketFilter subclass called WicketGuiceFilter in order to utilize our provider and wire it into wicket's IWebApplicationFactory:
@Singleton
public class WicketGuiceFilter extends WicketFilter {

 @Inject private Provider<WebApplication> appsProvider;
 
 @Override
 protected IWebApplicationFactory getApplicationFactory() {
  return new IWebApplicationFactory() {   
   @Override
   public WebApplication createApplication(WicketFilter filter) {    
    return appsProvider.get();
   }
  };
 } 
}
The reason I chose to subclass WicketFilter instead of doing this inside configureServlets():
Map<String, String> params = new HashMap<String, String>();
 
 params.put(WicketFilter.APP_FACT_PARAM, WicketGuiceAppFactory.class.getName());
 filter("/*").through(WicketFilter.class, params);
Is that WicketFilter instantiates the factory via reflection and the prevents Guice from doing its work.

This concludes our integration, would love to hear any comments.

You can download just the full source of this post and web.xml here

OR

You can download a full eclipse dynamic web project with dependencies included, you will need to import it to your workspace and reconfigure a servlet container runtime (such as apache tomcat) before you can build.

OR

Get the above eclipse project via svn or simply browse the code for your convenience here:
https://www.codeark.com/svn/wicket.guice.alt/trunk
This repository is read only for anonymous access.

Thursday, May 13, 2010

HOWTO: Open a webpage programmatically in an android java application

Using an intent like this:

Intent intent = new Intent("android.intent.action.VIEW", Uri.parse("http://www.codeark.com"));

try {
 this.startActivity(intent);
} catch (ActivityNotFoundException ex) {
 // do something about the exception, or not ...
}


"this" is the Context.

more info here: Context.startActivity()

Wednesday, May 5, 2010