Accessibility

Table of Contents

The Flex, Spring and BlazeDS full stack – Part 3: Putting the application together

Exposing the Spring service via BlazeDS

In the previous section we set up the configuration files in their own module, in order to make it easy to distribute (and not duplicate) them later. In this section, we'll take a look at how to expose the to do list service via BlazeDS so that our Flex client can consume it.

First, we need to add the BlazeDS libraries to the web module dependencies. This part involves editing the todolist-web/pom.xml file to add the following dependencies:

<dependency>
  <groupId>com.adobe.blazeds</groupId>
  <artifactId>blazeds-common</artifactId>
  <version>3.0.0.544</version>
</dependency>
<dependency>
  <groupId>com.adobe.blazeds</groupId>
  <artifactId>blazeds-core</artifactId>
  <version>3.0.0.544</version>
</dependency>
<dependency>
  <groupId>com.adobe.blazeds</groupId>
  <artifactId>blazeds-remoting</artifactId>
  <version>3.0.0.544</version>
</dependency>
<dependency>
  <groupId>backport-util-concurrent</groupId>
  <artifactId>backport-util-concurrent</artifactId>
  <version>3.1</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
</dependency>

BlazeDS libraries (blazeds-core, blazeds-common and blazeds-remoting) are currently only available from my personal repository—until they are published to a public repository. The code above adds the BlazeDS libraries to the project, and now we'll add a special Java class to the project. This Java class acts as a bridge between BlazeDS and Spring by retrieving Spring bean instances for the BlazeDS FlexFactory interface. The entire org.epseelon.samples.todolist.controller.SpringFactory class is presented below (courtesy of Jeff Vroom):

package org.epseelon.samples.todolist.controller;
 
import flex.messaging.FactoryInstance;
import flex.messaging.FlexFactory;
import flex.messaging.config.ConfigMap;
import flex.messaging.services.ServiceException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
 
public class SpringFactory implements FlexFactory {
  private static final String SOURCE = "source";
 
  public void initialize(String id, ConfigMap configMap) {
  }
 
  public FactoryInstance createFactoryInstance(String id, ConfigMap properties) {
    SpringFactoryInstance instance = new SpringFactoryInstance(this, id, properties);
    instance.setSource(properties.getPropertyAsString(SOURCE, instance.getId()));
    return instance;
  } // end method createFactoryInstance()
 
  public Object lookup(FactoryInstance inst) {
    SpringFactoryInstance factoryInstance = (SpringFactoryInstance) inst;
    return factoryInstance.lookup();
  }
 
  static class SpringFactoryInstance extends FactoryInstance {
    SpringFactoryInstance(SpringFactory factory, String id, ConfigMap properties) {
      super(factory, id, properties);
    }
 
    public String toString() {
      return "SpringFactory instance for id=" + getId() + " source=" + getSource() + " scope=" +
        getScope();
    }
 
    public Object lookup() {
      ApplicationContext appContext = WebApplicationContextUtils.getWebApplicationContext(flex.messaging.FlexContext.getServletConfig().getServletContext());
 
      String beanName = getSource();
      try {
        return appContext.getBean(beanName);
      } catch (NoSuchBeanDefinitionException nexc) {
        ServiceException e = new ServiceException();
        String msg = "Spring service named '" + beanName
          + "' does not exist.";
        e.setMessage(msg);
        e.setRootCause(nexc);
        e.setDetails(msg);
        e.setCode("Server.Processing"); 
 
        throw e;
      } catch (BeansException bexc) {
        ServiceException e = new ServiceException();
        String msg = "Unable to create Spring service named '"
          + beanName + "' ";
        e.setMessage(msg);
        e.setRootCause(bexc);
        e.setDetails(msg);
        e.setCode("Server.Processing");
        throw e;
      }
    }
  }
}

The next step involves configuring the servlet that is responsible for handling remoting requests coming from the Flex UI. This servlet is responsible for calling the Spring service when needed. Add the following configuration to todolist-web/src/main/webapp/WEB-INF/web.xml, just after listener configuration:

<context-param>
  <param-name>flex.class.path</param-name>
  <param-value>/WEB-INF/flex/hotfixes</param-value>
</context-param>
 
<!-- MessageBroker Servlet -->
<servlet>
  <servlet-name>MessageBrokerServlet</servlet-name>
  <servlet-class>
    flex.messaging.MessageBrokerServlet
  </servlet-class>
  <init-param>
    <param-name>services.configuration.file</param-name>
    <param-value>/WEB-INF/flex/services-config.xml</param-value>
  </init-param>
  <init-param>
    <param-name>flex.write.path</param-name>
    <param-value>/WEB-INF/flex</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>

As you can see, this servlet needs some configuration files to work. More specifically, it requires the files that are inside the shared configuration module that we created in the first section of this article.

In order to import these files, we need to include our shared configuration module as a dependency of the web module. To do this, add the following dependency to todolist-web/pom.xml:

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>todolist-config</artifactId>
    <version>1.0-SNAPSHOT</version>
    <classifier>resources</classifier>
    <type>zip</type>
    <scope>provided</scope>
</dependency>

Then, in order to unpack those configuration files and embed them in your web application, you'll need to add the following plug-in configuration to the build section in todolist-web/pom.xml:

<plugin>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>unpack-config</id>
      <goals>
        <goal>unpack-dependencies</goal>
      </goals>
      <phase>generate-resources</phase>
      <configuration>
        <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/flex</outputDirectory>
        <includeArtifacIds>todolist-config</includeArtifacIds>
        <includeGroupIds>${project.groupId}</includeGroupIds>
        <includeClassifiers>resources</includeClassifiers>
        <excludeTransitive>true</excludeTransitive>
        <excludeTypes>jar,swf</excludeTypes>
      </configuration>
    </execution>
  </executions>
</plugin>

Now, review the code in todolist-config/src/main/resources/services-config.xml. The most interesting part is the destination configuration. Be sure to check out the section where the todoService destination is defined that uses the BlazeDS SpringFactory for handling. The key is that the source parameter corresponds to the bean ID of the service.

There is one more thing left to do in order to allow Maven to build todolist-web independently from the other modules. The Maven plug-in flex-mojos defines a resource-bundle packaging that maven-war-plugin is not aware of. To solve that issue, add the following plug-in configuration:

<plugin>
  
<groupId>info.rvin.mojo</groupId>
   <artifactId>flex-compiler-mojo</artifactId>
  
<extensions>true</extensions>
</plugin>

Finally, run 'mvn install' to check that everything is working. Double-check that both configuration files are present in WEB-INF/flex.

At this point the to do service is exposed for remoting via BlazeDS. That's a big piece of the back end puzzle. In the next section, I'll describe the process for setting up the client-side connection.