Posts Tagged ‘injection’

Guice BlazeDS’ MessageBroker

4 Comments »

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.

Using Guice with Flex remoting for BlazeDS

1 Comment »

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.

Spring annotations static injection tutorial

12 Comments »

Spring’s architecture isn’t very friendly to static classes and methods.  It doesn’t have any way of injecting static properties of classes because it doesn’t have any way to discover them.  Spring’s designers have acknowledged that it’s a shortcoming of the framework and suggest the use of this solution.

  1. Create the static property of the class without any annotations
  2. Mark the class to have static properties injected with @Component so that the properties will be injected on Spring startup
  3. Create a non-static setter method that sets the static property
  4. Mark the setter method with @Autowired(required = true)
@Component
public class UserUtils
{
  private static UserAccessor userAccessor;
 
  /**
   * Sets the user DAO. This method should never be called except by Spring
   * @param userAccessor The user accessor to set
   */
  @Autowired(required = true)
  public void setUserAccessor(userAccessor UserAccessor) {
    UserUtils.userAccessor = userAccessor;
  }
}

Using this technique, you can have all of the advantages of Spring injection without the headaches of Spring injection!  Avoid using this technique whenever possible.  It should only be used to support legacy applications.  With a lot of statically stored values, your application will not scale well.