A New Gradle Grails Plugin

My team wanted to use Gradle to build our Grails project.  We had some trouble with version compatibility problems between Grails and the Grails build plugin, though.  Instead of using the plugin, we tried writing some code that called the ‘grails’ command directly, but that caused problems with the CI server because it required that the correct version of Grails be preinstalled on all build servers and exist in a known location.  I decided to try my hand at writing a simpler Grails build plugin and this is what I came up with.  It doesn’t require Grails to be pre-installed on the machine and, since it just executes the ‘grails’ command, it works with any version.

Fork it!  Or just use it 🙂

Gradle Grails Wrapper

Posted in Gradle, Groovy at April 6th, 2012. 5 Comments.

Formatting JSON and XML in Gedit

Here’s how to add commands to Gedit to format JSON and XML documents.

  1. Ensure that you have an up-to-date version of Python.  It’s included with nearly every Linux distribution.
  2. Ensure that the External Tools plugin is installed
    1. Click Edit -> Preferences
    2. Select the Plugins tab
    3. Check the box next to External Tools
    4. Click Close
  3. Add the Format JSON command
    1. Click Tools -> Manage External Tools…
    2. Click New (bottom left, looks like a piece of paper with a plus sign)
    3. Enter a name (Format JSON)
    4. Paste this text into the text window on the right
      #! /usr/bin/env python
       
      import json
      import sys
       
      j = json.load(sys.stdin)
      print json.dumps(j, sort_keys=True, indent=2)
    5. Set Input to Current document
    6. Set Output to Replace current document
  4. Add the Format XML command
    1. Install lxml (on Ubuntu, sudo apt-get install python-lxml)
      1. Python’s included XML modules either don’t support pretty printing or are buggy
    2. Create a new external tool configuration as above (Format XML)
    3. Paste this text into the text window on the right
      #! /usr/bin/env python
       
      import sys
      import lxml.etree as etree
      import traceback
       
      result = ''
      for line in sys.stdin:
        result += line
      try:
        x = etree.fromstring(result)
        result = etree.tostring(x, pretty_print=True, xml_declaration=True, encoding=”UTF-8″)
      except:
        etype, evalue, etraceback = sys.exc_info()
        traceback.print_exception(etype, evalue, etraceback, file=sys.stderr)
      print result
    4. Set Input to Current document
    5. Set Output to Replace current document

Thanks to Diego Alcorta for improvements that preserve XML declarations and set encoding!

Posted in Python at November 22nd, 2011. 34 Comments.

A Yammer App Using Gaelyk for Google App Engine

I recently attended a presentation by Tim Berglund about Gaelyk at Uberconf.  The technology of Gaelyk is pretty straightforward and doesn’t need much of an introduction, especially with the excellent tutorial available on its web site.  Watching the presentation, I was struck by how little there is to Gaelyk and wondered why I was there.  Sitting in a room of developers and coding a working, useful application in just over an hour, though, reminded me about how much fun web programming can be.  Many of us have become so accustomed to frameworks like Struts, WebMVC, GWT and Grails that we’ve forgotten the simpler times, when you could slap together some Servlets and JSPs and have fun putting together a small, useful app.  Gaelyk brings back those simpler times and makes them even more enjoyable by adding the conveniences of Groovy and App Engine.

I picked an app that I wanted to code, something that would tell Yammer users what their companies are talking about.  It’s available for anyone to use at http://whatyammer.appspot.com.

Data access

Want to save a record to the database?  Forget about messing around with bean and data access classes, database connections and ORM.  No need to create tables.  You’re coding for fun!

def user = new Entity('user')
user.email = params.email
user.name = params.name
user.phone = params.phone
user.save()

That’s all.  To get that record back out

datastore.execute {
  select single from user
  where email == params.email
}

Forwarding objects to a view

Gaelyk views are coded in gtpl files, which are much like JSPs. The controller, echo.groovy

request.users = datastore.execute { select all from user where email == params.email }
forward 'showusers.gtpl'
The view, showusers.gtpl
Adventure Time with <%= (request.users*.name).join(' and ') %>
That prints the names of all users, with the word and between each one.  That is just a small taste of what Gaelyk makes available.  So simple!  So much fun!  Single-command deployment!  Google will host 10 apps for free, so there isn’t any reason not to try it out.  Just note that before you deploy, you have to visit http://appengine.google.com and register your new app or Google will give you a very unhelpful error message.

Posted in Groovy at August 19th, 2011. No Comments.

Functional Test and Integration Test Targets in Gradle

* Update February 13th, 2012: Thanks to Ben Ripkens for updates to match the new Gradle API.

While searching online, I found many suggestions for how to add a new test target to a Gradle script. Most of them were wrong and others didn’t properly separate the integration test target from standard targets. After not finding a solution, I came up with one on my own.

This example sets up integration tests for Groovy .

Create a source set

This will separate the integration test code from other code, allowing it to be built separately.

  • The classpath in the example gives integration tests access to all application and test classes
  • The source location will be src/integrationTest/groovy
sourceSets {
  integrationTest {
    compileClasspath = sourceSets.main.output + configurations.testRuntime
    runtimeClasspath = output + sourceSets.main.output + configurations.testRuntime
    groovy {
      srcDir 'src/integrationTest/groovy'
    }
  }
}

Add the target

 

task integrationTest(type: Test) {
  testClassesDir = sourceSets.integrationTest.output.classesDir
  classpath = sourceSets.integrationTest.runtimeClasspath
}

 

Posted in Java at January 11th, 2011. 3 Comments.

Antcall vs Depends

Occasionally, I see issues pop up on Java projects about builds not working properly.  They usually look like, “The build worked yesterday, but it doesn’t work today.  I was working on it, but I didn’t change anything related to the part that is failing.” or “I can’t figure out why, when I run this by itself, it passes.  When I run it as a part of a full build, it fails.”  Build errors are almost always caused by a misunderstanding of the function of “depends”.

How Not to Use Depends

This probably works, but only by chance.

<target name="test" depends="clean,compile,compile-test,test,service-test" />

Depends is not a list of tasks to be executed.  It’s a list of dependencies that must be satisfied before a target can be completed.  Execution is not guaranteed and side effects are common.  Take a close look at what each of the tasks in the following script is doing.

<target name="functional-test" depends="start-server,run-tests,stop-server" />
<target name="service-test" depends="start-server,run-service-tests,stop-server" />
<target name="test" depends="clean,compile,compile-test,functional-test,service-test" />

To a human, the intent is obvious.

  1. Clean and compile
  2. Start server
  3. Run functional tests
  4. Stop server
  5. Start server
  6. Run service tests
  7. Stop server

But Ant will not execute those tasks.  Since they were declared as dependencies, Ant evaluates them as such.  The functional tests will run as you would expect.  When it runs the service-test target, though, it will see the start and stop server tasks again.  As far as it’s concerned, those dependencies have already been satisfied, so it will skip start-server and stop-server.  Ant is evaluating the script correctly, but the script is wrong.

Dependencies are not tasks to be executed.  They are dependencies.  Once a dependency has been satisfied, it will not be executed again.

Antcall Is Not Evil

It exists for a reason.  Use it when it is useful.  Dependencies are dependencies, not task lists.  In this case, it would be impractical to try to write the script to use depends attributes to cause events to happen correctly.  It can be fixed very easily by using antcall.  Each antcall is evaluated separately, so you don’t have to worry about side effects like the script above.  It’s also easier to read.  You can see what’s intended to happen before this target and you can see what this target is intended to do.

<target name="functional-test" depends="start-server,run-tests,stop-server" />
<target name="service-test" depends="start-server,run-service-tests,stop-server" />
<target name="test" depends="clean,compile,compile-test">
  <antcall target="functional-test" />
  <antcall target="service-test" />
</target>

Use Your Own Judgement

Obviously, antcall should not be used instead of depends.  Depends is far more useful.  But don’t throw a tool like antcall away just because it doesn’t seem as cool or concise or elegant.

Posted in Java at September 17th, 2010. 4 Comments.

A threaded Go language application with semaphores

After hearing about Go and its love of parallelism, I wanted to give it a try. I couldn’t think of any small projects that needed to be threaded until recently.  My employer uses an RPM system, but I’m using Ubuntu, which requires deb files.  Searching through the RPMs in a browser is a pain, so I wanted a small script that would search for me.  Here’s the script with server names changed.

package main

import (
  "bufio"
  "fmt"
  "http"
  "os"
  "regexp"
  "strings"
)

var servers = []string {
  "http://www.google.com/search?client=ubuntu&channel=fs&q=go+language&ie=utf-8&oe=utf-8",
  "http://golang.org/",
  "http://golang.org/doc/go_tutorial.html"}

var maxOpenRequests int = 3

var rpmRegexp = regexp.MustCompile("href=\"[^\"]+\"")

func main() {
  search := getSearchTerm()
  out := make(chan string)
  done := make(chan int)
  go printer(out)
  for _, url := range servers {
    go searchURL(search, url, out, done)
  }
  for i := 0; i < len(servers); i++ {
    <- done
  }
}

func getSearchTerm() string {
  args := os.Args
  if len(args) != 2 {
    die("Please enter one search term")
  }
  return args[1]
}

func die(message string) {
  fmt.Println(message)
  os.Exit(1)
}

func printer(out chan string) {
  for {
    fmt.Println(<- out)
  }
}

var requestSemaphore = make(chan int, maxOpenRequests) // Integer chanel with a maximum queue size

func searchURL(search string, url string, out chan string, done chan int) {
  requestSemaphore <- 1 // Block until put in the semaphore queue
  response, realURL, err := http.Get(url)
  if err == nil {
    bufferedReader := bufio.NewReader(response.Body)
    err = searchAll(search, bufferedReader, url, out)
    response.Body.Close()
  }
  if err != nil {
    die("Could not read from " + realURL + ":" + err.String())
  }
  <- requestSemaphore // Dequeue from the semaphore
  done <- 1 // Signal that function is done
}

func searchAll(search string, reader *bufio.Reader, httpRoot string, out chan string) (os.Error) {
  var error os.Error = nil;
  for {
    var line, err = reader.ReadString('\n')
    if err != nil {
      if err == os.EOF {
        break
      }
      return error
    }
    var hrefs = rpmRegexp.AllMatchesStringIter(line, 0)
    for href := range hrefs {
      start := strings.Index(href, "\"") + 1
      end := len(href) - 1
      packageFile := href[start : end]
      if strings.Index(packageFile, search) != -1 {
        out <- httpRoot + packageFile
      }
    }
  }
  return error
}

A quick overview

Go uses “channels” for communication among threads.

  1. The main thread creates two channels, one to receive search output and one to receive “done” responses when a child thread finishes.
  2. The main thread attaches the output channel to a simple function that prints to standard out.
  3. The main thread spawns one child thread per server, giving each the output and done channels.
  4. The main thread loops over the done channel once for each server, waiting until all requests are complete.
  5. Each child blocks immediately until space is available in a semaphore.
  6. The child performs the HTTP get, then searches the response for anything matching a regular expression.  Any matches are signaled back to the output channel.
  7. The child opens a space in the semaphore and signals to the main thread that it is done.

There isn’t much more to say.  The Go web site has great tutorials, so I don’t yet feel the need to write one.

By the way, if you’re searching for Go resources, be sure to search for “go language” and not “go”.  But then, that’s probably how you found this page 😉

package main

import (
“bufio”
“fmt”
“http”
“os”
“regexp”
“strings”
)

var servers = []string {
“http://apt.duncllc.com/dist/WS4.0/RedHat/RPMS/”,
“http://apt.duncllc.com/dist/WS4.0/RedHat/RPMS.extras/”,
“http://apt.duncllc.com/dist/WS4.0/RedHat/RPMS.java/”}

var maxOpenRequests int = 3

var rpmRegexp = regexp.MustCompile(“href=\”[^\”]+\””)

func main() {
search := getSearchTerm()
out := make(chan string)
done := make(chan int)
go printer(out)
for _, url := range servers {
go searchURL(search, url, out, done)
}
for i := 0; i < len(servers); i++ {
<- done
}
}

func getSearchTerm() string {
args := os.Args
if len(args) != 2 {
die(“Please enter one search term”)
}
return args[1]
}

func die(message string) {
fmt.Println(message)
os.Exit(1)
}

func printer(out chan string) {
for {
fmt.Println(<- out)
}
}

var requestSemaphore = make(chan int, maxOpenRequests) // Integer chanel with a maximum queue size

func searchURL(search string, url string, out chan string, done chan int) {
requestSemaphore <- 1 // Block until put in the semaphore queue
response, realURL, err := http.Get(url)
if err == nil {
bufferedReader := bufio.NewReader(response.Body)
err = searchAll(search, bufferedReader, url, out)
response.Body.Close()
}
if err != nil {
die(“Could not read from ” + realURL + “:” + err.String())
}
<- requestSemaphore // Dequeue from the semaphore
done <- 1 // Signal that function is done
}

func searchAll(search string, reader *bufio.Reader, httpRoot string, out chan string) (os.Error) {
var error os.Error = nil;
for {
var line, err = reader.ReadString(‘\n’)
if err != nil {
if err == os.EOF {
break
}
return error
}
var hrefs = rpmRegexp.AllMatchesStringIter(line, 0)
for href := range hrefs {
start := strings.Index(href, “\””) + 1
end := len(href) – 1
packageFile := href[start : end]
if strings.Index(packageFile, search) != -1 {
out <- httpRoot + packageFile
}
}
}
return error
}

Posted in Go at May 21st, 2010. No Comments.

Python Package Structure with Unit Testing, Injection and Mocking

Python is a language that some people like and use.  I recently was given a small Python application and had to refactor it so that I could implement unit and functional tests.  It took me a while to find the resources and learn how to implement them, so I thought I’d write it up here.

* Please note that this is not a unit testing tutorial.  Those are plentiful and can be found elsewhere.  This describes setting up a professional Python project with a real package structure, injection and tests.

Python Project Structure

Python was conceived as a scripting language.  Unlike compiled languages like C or Java, Python files are designed to be directly runnable.

  • RunMe.java -p someargument < Not ok!
  • RunMe.py -p someargument < Ok!

This is convenient for small scripts, but doesn’t help applications.  Since you are intended to run .py files directly, Python projects should not have source (src) or binary (bin) folders.  Having a source folder makes a program difficult to run.  The root of the Python package structure should be the root of the project.

For the same reason, the test folder should not be separate.  It should be a package in the main project.  Since the root folder is the root package, you won’t have much choice.

Example

  • MyProject
    • __init__.py
    • model
      • __init__.py
      • user.py
    • service
      • __init__.py
      • user_service.py
      • ldap_user_service.py
    • test
      • __init__.py
      • unit
        • __init__.py
        • service
          • __init__.py
          • user_service_test.py
      • functional
        • __init__.py
        • service
          • __init__.py
          • user_service_test.py

If you’re new to Python, please note that those __init__.pys are required.  They tell Python which folders contain Python files.  This is Python’s way of allowing you to have other folders, such as config, that don’t contain source files.

Note

You should specify exactly one class per file.  It makes your code easier to find and read.

Injection with snake-guice

Injection is essential for unit tests.  In the example above, LDAPUserService may connect to an LDAP server to retrieve information, something we don’t want to happen in unit tests.

I’ve been using snake-guice and highly recommend it.

Install snake-guice, Mock and nose

If you don’t have it, grab a copy of easy install.  Then, $ sudo easy_install.py snake-guice Mock nose.  That installs packages from PyPI, the Python Package Index.  For those used to non-scripting languages, this may not seem like a great way to use external libraries.  Since Python is a scripting language, however, it’s the only way that makes sense.

Create a module and use it to instantiate your application

class ExampleModule:
  def configure(self, binder)
    binder.bind(UserService, to=LDAPUserService)
class ExampleRunner:
  user_service = None
 
  @inject(user_service=UserService)
  def __init__(self, user_service):
    self.user_service = user_service
 
  def main(user_service)
    self.user_service.login("name", "password")
injector = Injector(ExampleModule)
runner = injector.get_instance(ExampleRunner)

When get_instance is called, injector will use the ExampleModule to discover bindings.  Then, it will create an ExampleRunner, passing in arguments specified by @inject.

The setUp method of PyUnit tests should create an injector with a TestExampleModule, which should be configured to return mocks.

class TestExampleModule:
  def user_service = Mock()
 
  def configure(self, binder)
    binder.bind(UserService, to=user_service)
class ExampleTest(TestCase):
  application = None
 
  def setUp(self):
    Injector = Injector(TestExampleModule)
    self.application = injector.get_instance(ExampleApplication)
 
  def test_something(self):
    application.user_service.search.return_value = "expected"
    actual = application.user_service.search("any")
    self.assertEquals(expected, actual)

Since setUp is called before each test, each test method gets a fresh mock that it can configure any way it likes.

Similarly, a functional test module can be created that connects to a local or testing server.

Mocking with Mock

I recommend using Mock for mocking, which is why I had you install it earlier.  Be careful when searching for it because there appear to be two projects called Mock.

The Mock package is well documented.  Please go to the Mock site for more information.

Running Tests

For running tests, I recommend Nose.  To run your tests, open a command line and change to your root project folder.  Then, nosetests.  Nose will take care of adding the packages you installed earlier, snake-guice and Mock, to the Python path.  It will also find all tests, run them and report the results.  Handy!

$ cd ~/exampleproject
$ nosetests

To run only unit or functional tests, use the -w argument.

$ nosetests -w ./ ./test/unit
$ nosetests -w ./ ./test/functional

Is that all?

To those who have not used injection or mocks for testing, this may seem like a lot of work.  I hope you’ll try it, though, because it’s a one-time setup.  Once these good practices are in place, you’ll find that all of your code organization and testing becomes simple and almost automatic.  If I missed something or if you have any suggestions, please post below.

Posted in Python at February 6th, 2010. 7 Comments.

HTC T-Mobile G1 vs Motorola CLIQ

I owned a G1 for just over a year and it was lost or stolen.  Having used Android for so long, I couldn’t live without it for 7 months until I was eligible for an upgrade.  I stopped by the T-Mobile store to get a replacement G1, but was pleasantly surprised to find that the CLIQ was the same price.  I knew it was faster and had a headphone jack (yes!), so I picked it up.

It always takes time to get used to a new phone, but even after a month of use, I wasn’t blown away by the CLIQ.

  • The basics, things that you can read in the phone specs
    • The G1 has a larger screen.  It’s not a big difference on paper, but is quite noticeable in use.
    • The CLIQ has a headphone jack, meaning you can listen to music with standard earbuds or headphones or plug it in to your car’s stereo and charge it at the same time without having to buy and tote around a custom dongle.
  • Speed – CLIQ
    • Although they have the same processor, the CLIQ wins here pretty handily.  Even after all of the updates between Android 1.0 and 1.6, the G1 was always sluggish.  Some applications slowed it down so much that it became unusable and had to be rebooted.
  • Battery – CLIQ
    • The G1 had to be recharged at least once a day.  During a day of heavy use, it needed more than one charge.  The CLIQ won’t go for days on a charge like some non-smart phones, but it easily outlasts the G1.
  • Keyboard – G1
    • People may complain about the G1’s rotate-out-slider feature, but it allows the G1 a gigantic, easy-to-use keyboard by phone standards.  Traditional sliders, like the CLIQ’s, can only go so far up before they become wobbly and prone to breaking.  The G1’s screen is completely separate from the main body except for the connection at the bottom (or right), allowing it to slide much farther up.  The G1’s keys are also better designed.  They’re just as responsive as the CLIQ’s, but without the annoying, well, clicks made by the … CLIQ.
  • D-pad / Trackball – G1
    • The CLIQ’s directional pad works just as well as the G1’s trackball.  Each design has it’s benefits.  The trackball lets you zoom through text or selections, but it’s difficult to press without accidentally rotating it at the same time.  I’ll never figure out why the CLIQ’s designers decided to hide the d-pad under the screen, though.  It’s really a pain to have to slide the keyboard out and rotate the screen just to get access to it.  One major score for the G1.
  • UI – G1
    • Phone manufacturers can never leave an operating system alone.  Imagine if Windows were customized so that it worked completely differently on a Sony than on an HP. Luckily, Motorola didn’t go as far as others (like Samsung).  Still, the stock Android OS looks much better than Motorola’s.
  • OS – G1
    • Here, too, Motorola’s decision to customize Android is a problem.  HTC can update Android on the G1 by adding device-specific code.  For a CLIQ update, Motorola has to merge the entire Android codebase with their own fork.  This means CLIQ updates lag behind other devices.  The G1 has had Android 1.6 for a while.  The CLIQ is still on 1.5 and won’t be updated until Motorola releases 2.1 for it.  Maybe.
  • Touchability – G1
    • Many users (including me) have had problems with the CLIQ’s capacitive touch screen.  Sometimes it works flawlessly and sometimes it doesn’t.  It’s especially annoying when playing games.
  • Exterior appearance – CLIQ
    • The CLIQ’s bold lines and attractive coloring outshine the boring G1.  I highly recommend the titanium white version.
  • Sturdiness – CLIQ
    • With a more solid construction and a responsive slider mechanism, the CLIQ feels much better in the hand.
Posted in Android at December 22nd, 2009. 9 Comments.

Guice BlazeDS’ MessageBroker

In a previous post (http://www.connorgarvey.com/blog/?p=132), I wrote about how to use Guice injection for Flex services.  I used web.xml to configure the MessageBrokerServlet and configured each Flex service to use Guice as a factory.  Since then, on this project, we’ve had to introduce new servlets.  Rather than continue to use web.xml’s verbose and fully-qualified-path based configuration, we moved to using Guice’s ServletModule class.  Here are the steps we followed.

  1. Ensure the guice-servlet.jar is included in your project and is deployed with your build.
  2. Add the Guice filter to web.xml.
    <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>
  3. Create a servlet module, a class extending com.google.inject.servlet.ServletModule.
  4. Override the configureServlets() method of ServletModule and add the message broker servlet configuration.
    this.bind(MessageBrokerServlet.class).in(Scopes.SINGLETON);
    final Map<String, String> params = new TreeMap<String, String>();
    params.put("services.configuration.file", this.context
        .getRealPath("WEB-INF/config/flex/services-config.xml"));
    this.serve("/messagebroker/*").with(MessageBrokerServlet.class, params);

    1. Normally, servlets configured in Guice are tagged with @Singleton.  Since the MessageBrokerServlet is third party, it’s marked as a singleton here, in the module.
  5. Add the new module to the Guice servlet context listener, which should already be configured in web.xml.
  6. Remove the servlet and servlet-mapping from web.xml.
Posted in Guice at October 20th, 2009. 4 Comments.

Using Guice with Flex remoting for BlazeDS

I just finished putting a server together that uses Google’s Guice and Adobe’s BlazeDS.  Here’s how you can quickly get a project working using the same configuration.

* Update: A new post describes using Guice’s ServletModule to configure the MessageBrokerServlet.

Download the libraries

Download Guice and BlazeDS.  Use the project configured in the BlazeDS war to get started.

Create the Guice factory

Since BlazeDS provides the servlet, you won’t be able to configure your classes using Guice unless you have a Flex factory.  This code will inject itself with Guice to get instances of Flex services.

package com.connorgarvey.guiceblazeds.servlet;
 
import java.util.HashMap;
import java.util.Map;
import com.google.inject.Injector;
import flex.messaging.FactoryInstance;
import flex.messaging.FlexContext;
import flex.messaging.FlexFactory;
import flex.messaging.config.ConfigMap;
import flex.messaging.services.ServiceException;
 
/**
 * <p>A Flex factory that retrieves instances of Flex services from Guice</p>
 * <p>This is based on a similar factory built for Spring by Jeff Vroom</p>
 * @author Connor Garvey
 * @created May 27, 2009 1:09:49 PM
 * @version 1.0.0
 * @since 1.0.0
 */
public class GuiceFactory implements FlexFactory {
  private static final String SOURCE = "source";
 
  /**
   * @see flex.messaging.FlexFactory#createFactoryInstance(java.lang.String, flex.messaging.config.ConfigMap)
   */
  public FactoryInstance createFactoryInstance(final String id, final ConfigMap properties) {
    final GuiceFactoryInstance instance = new GuiceFactoryInstance(this, id, properties);
    instance.setSource(properties.getPropertyAsString(SOURCE, instance.getId()));
    return instance;
  }
 
  /**
   * @see flex.messaging.FlexConfigurable#initialize(java.lang.String, flex.messaging.config.ConfigMap)
   */
  public void initialize(final String id, final ConfigMap configMap) {
  }
 
  /**
   * @see flex.messaging.FlexFactory#lookup(flex.messaging.FactoryInstance)
   */
  public Object lookup(final FactoryInstance inst) {
    return inst.lookup();
  }
 
  static class GuiceFactoryInstance extends FactoryInstance {
    private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
    GuiceFactoryInstance(final GuiceFactory factory, final String id, final ConfigMap properties) {
      super(factory, id, properties);
    }
 
    @Override
    public Object lookup() {
      final Injector injector = (Injector)FlexContext.getServletContext().getAttribute(
          GuiceServletContextListener.KEY);
      injector.injectMembers(this);
      String className = this.getSource();
      Class<?> clazz = this.classes.get(className);
      if (clazz == null) {
        try {
          clazz = Class.forName(this.getSource());
          this.classes.put(className, clazz);
        }
        catch (ClassNotFoundException ex) {
          ServiceException throwing = new ServiceException();
          throwing.setMessage("Could not find remote service class '" + this.getSource() + "'");
          throwing.setRootCause(ex);
          throwing.setCode("Server.Processing");
          throw throwing;
        }
      }
      return injector.getInstance(clazz);
    }
 
    @Override
    public String toString() {
      return "Guice factory <id='" + this.getId() + "',source='" + this.getSource() +
          "',scope='" + this.getScope() + "'>";
    }
  }
}

Create a context listener

The Guice servlet jar contains a ServletContextListener, but I haven’t taken the time to integrate it into this solution.  For simplicity, you can use this one, which works with the factory above.

package com.connorgarvey.guiceblazeds.servlet;
 
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
 
/**
 * Prepares Guice on application startup
 * @author Connor Garvey
 * @created May 27, 2009 8:37:26 AM
 * @version 1.0.0
 * @since 1.0.0
 */
public abstract class GuiceServletContextListener implements ServletContextListener {
  /**
   * The key of the servlet context attribute holding the injector
   */
  public static final String KEY = Injector.class.getName();
 
  /**
   * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
   */
  public void contextDestroyed(final ServletContextEvent servletContextEvent) {
    servletContextEvent.getServletContext().removeAttribute(KEY);
  }
 
  /**
   * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
   */
  public void contextInitialized(final ServletContextEvent servletContextEvent) {
    servletContextEvent.getServletContext().setAttribute(KEY,
        this.getInjector(servletContextEvent.getServletContext()));
  }
 
  private Injector getInjector(final ServletContext servletContext) {
    return Guice.createInjector(this.getModules());
  }
 
  /**
   * Gets the modules used by the application
   * @return the modules
   */
  protected abstract List<? extends Module> getModules();
}

Extend GuiceContextListener

Create a concret version of the class above.  It should return all modules needed for the application.

Modify web.xml

Now, prepare web.xml with the normal BlazeDS settings plus some extras for Guice.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>Guice BlazeDS</display-name>
  <description>Guice BlazeDS</description>
  <listener>
    <listener-class>flex.messaging.HttpFlexSession</listener-class>
  </listener>
  <listener>
    <listener-class>com.connorgarvey.guiceblazeds.servlet.MyCustomGuiceServletContextListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>MessageBrokerServlet</servlet-name>
    <display-name>MessageBrokerServlet</display-name>
    <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
    <init-param>
      <param-name>services.configuration.file</param-name>
      <param-value>/WEB-INF/config/flex/services-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>MessageBrokerServlet</servlet-name>
    <url-pattern>/messagebroker/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
  </welcome-file-list>
</web-app>

This way, BlazeDS will start at server startup, followed by Guice.

Modify BlazeDS config

Open services-config.xml and add this at the top of the file.  Point it to the Guice factory.

<?xml version="1.0" encoding="UTF-8"?>
<services-config>
  <factories>
    <factory id="guice" class="com.connorgarvey.guiceblazeds.servlet.GuiceFactory" />
  </factories>

Set the factory of all remoting destinations

In remoting-config.xml, be sure to set the factory of all destinations to the name specified in services-config.xml above.

<destination id="SomeService">
  <properties>
    <factory>guice</factory>
    <source>com.connorgarvey.guiceblazeds.service.flex.SomeFlexService</source>
  </properties>
</destination>

How this all works

  1. When the server starts, BlazeDS and Guice are initialized by the servlet listeners.
  2. When BlazeDS receives a request, to a service, it’ll see that it’s supposed to retrieve it from the “guice” factory.
  3. The Guice factory will return an instance of the class specified in the source of the service configuration from Guice to BlazeDS for use in completing the request.
Posted in Guice at June 19th, 2009. 1 Comment.