Sunday, October 28, 2012

Adding Guice to the GWT Sample Application

When you work on pre-existing projects most of the time, it's easy to take for granted the effort that can be involved in setting up all of the fancy infrastructure you've become accustomed to. I set up a new GWT application from scratch last week and while adding Guice support to the server side, I wasted some time because I forgot to disable the servlet that the Google Eclipse Plugin "New Project" wizard set up for me in web.xml.

So for fun, I looked on the web and was rather underwhelmed by the instructions for setting up Guice particularly in the GWT context. To help other people (including my future self), I will walk through it here, in a coherent manner in a single place. The following assumes you are starting from the result of the GWT "New Project" wizard (I called my project "GuiceStarter") and want to Guice-enable the GreetingService.

1. Download Guice, copy the .jar files into war/WEB-INF/lib, and add them to the Eclipse Build Path.
2. Create a module in the "server" package as follows:

public class GuiceStarterAppModule extends AbstractModule {
  @Override
  protected void configure() {
    bind(GreetingServiceImpl.class);
  }
}

3. Create the servlet listener config in the "server" package as follows:

public class GuiceServletConfig extends GuiceServletContextListener {

  @Override
  protected Injector getInjector() {
    return Guice.createInjector(new ServletModule() {
      @Override
      protected void configureServlets() {
        serve("/guicestarter/greet").with(GreetingServiceImpl.class);
      }
    }new GuiceStarterAppModule());
  }
}

4. In web.xml, take out the existing and for greetServlet.

5. In web.xml, add the Guice configuration:


<listener>
    <listener-class>com.scottmcmaster365.weatherapp.server.GuiceServletConfig</listener-class>
</listener>

<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>

6. Test this by modifying GreetingServiceImpl as follows:

@Singleton
public class GreetingServiceImpl extends RemoteServiceServlet implements
    GreetingService {

  @Inject
  public GreetingServiceImpl() {  // set a breakpoint here
  }
  // etc.

7. Set a breakpoint in the constructor, debug the Web Application, and make sure the breakpoint gets hit.
8. Start using Guice on the server-side as you normally would.

In a future post, I may also add Guice (Gin) to the client-side.

Friday, October 19, 2012

Selenium FirefoxProfile setProxyPreferences is @Deprecated++

I recently updated the Selenium and BrowserMob Proxy versions in WebTestingExplorer. WebTestingExplorer will proxy requests through BrowserMob, primarily to capture the HTTP response code because this is bafflingly but intentionally not supported in the WebDriver API. While you're here, surf over to Google Code and put a star on Selenium issue #141.

After I did this, I watched some tests running in WebTestingExplorer and noticed that certain HTTP form POSTs were not responding as expected. I've always thought that the WebDriver+BrowserMob setup seemed a little fragile (another reason why you should go star Selenium issue #141), so I instantly suspected it, and sure enough, when I pulled out the proxy, the form POSTs worked fine.

I took another look at the code where we set the proxy into the FirefoxProfile, which looked like this:

  @Override
  public WebDriver createWebDriver(WebDriverProxy proxy) throws Exception {
    if (proxy != null) {
      profile.setProxyPreferences(proxy.getSeleniumProxy());
    }
    return new FirefoxDriver(profile);
  }

What you can't see here but I saw in Eclipse was the @Deprecated strikethrough on the call to FirefoxProfile.setProxyPreferences: "This is now handled by the driver itself."

I figured that while I was settling in to debug this code anyway, I would remove the deprecation warning. So I updated to the new style as follows:

  @Override
  public WebDriver createWebDriver(WebDriverProxy proxy) throws Exception {
    DesiredCapabilities capabilities = DesiredCapabilities.firefox();
    capabilities.setCapability(FirefoxDriver.PROFILE, profile);
    if (shouldUseProxy) {
      capabilities.setCapability(CapabilityType.PROXY, proxy);
    }
    return new FirefoxDriver(capabilities);
  }

I run through my tests again. Now it works! Even though it is generally considered bad manners to break something when you @Deprecate it, I'm quite suspicious that the Selenium folks did that here.