BT

Spring BlazeDS Integration: What it Is and What Does it Change?

Posted by Ryan Knight on May 14, 2009 |

Adobe and Spring made a major announcement the end of last year that they where going to collaborate on a joint project called Spring BlazeDS Integration. The goal was to allow the Spring development model to be used for creating Rich Internet Applications (RIA's) with Adobe Flex, BlazeDS, Spring and Java. This would allow Spring managed services to be exposed through BlazeDS without the overhead of extra configuration files. The primary benefit is that it brings Spring ease of use to creating applications with Flex, BlazeDS and Java.

In this article I look at what the Spring BlazeDS Integration project changes and show a sample of how it works. First looking at how this changes the way applications are wired and how to easily convert an existing Spring project to use this new integration project. We finish up looking at the additional features and benefits of this project.

The sample application that is used through out is simple soda service that provides basic accounting information. The data model it uses is a SodaAccount that represents the client account information.

Developing Rich Internet Applications the Spring Way

When Spring was released it dramatically changed the way Java Server Side Development was done. It emphasized the use of plain old java objects (POJOs) wired together using Dependency Injection. This simplified development and testing of applications.

 

The core configuration of Spring is done with JavaBeans. With Beans, any Java classes can exposed as a service. For example, the following declares the Soda Service as a Spring Bean:

<!-- Implementation of soda bean-->
<bean id="sodaBean" class="com.gorillalogic.sodaBank.SodaService" init-method="initSodaAccounts">
	<property name="numAccounts" value="1000"/>
</bean>

For exporting these beans as Remote Services for Flex clients, the integration project uses Spring Web MVC. Spring Web MVC uses DispatchServlet as a central dispatcher for any type of HTTP request or HTTP-based remote services. The Dispatch Servlet is configured using the same JavaBeans configuration mechanism to forward requests to a handler adapter for processing.

Previously, a BlazeDS project would use the MessageBrokerServlet to route requests to the BlazeDS Message Broker. With Spring BlazeDS this is replaced with the Spring Web MVC DispatchServlet. The DispatchServlet is then configured to forward HTTP message to the MessageBrokerHandlerAdapter. This adapter is configured as a Spring factory bean. It creates a local a BlazeDS Message Broker instance within the Spring web application context. It is then used to export Spring beans as remote service that can be called for directly from Flex clients.

This approach to configuring the BlazeDS Message Broker allows for a tighter integration with Spring projects. It also reduces the configuration need for exporting Spring Beans as remote services. For example previously you had to declare a separate entry in messaging.xml to export your Java services. Now you simply wire a remoting export bean in the same file that you declare your Spring Beans.

Spring BlazeDS Integration does use some of the standard BlazeDS XML configuration files for configuring the messaging infastructure. This includes things such as channel dfinitions.

The next release of the project is adding integration with Spring Security. The initial implementation secures the BlazeDS endpoints using a pointcut advisor. Pointcut advisor are part of the Spring Aspect Oriented Programming (AOP) support.

Setting up a new Spring BlazeDS Integration Project - Server Side

Whether you are setting up a new project or adding the support to an existing project, the steps are fairly similiar. The first step is to add all of the needed jar files to your library directory. You can download them off the Spring Source website (http://www.springsource.org/spring-flex) or use the sample project library.

For this sample we will take a simple Soda Service project and modify it to use the Spring BlazeDS project. The first change is to the web.xml. In this file all references to the BlazeDS MessageBrokerServlet are removed. Instead a reference to the Spring DispatchServlet is used:

<servlet>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/config/web-application-config.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>


    <servlet-mapping>
        <servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
        <url-pattern>/gorilla/*</url-pattern>
    </servlet-mapping>

This routes all requests to the Dispatcher Servlet using the standard servlet mapping pattern. It also specifies the context configuration to point to web-application-config.xml.

The standard BlazeDS files are located in WEB-INF/flex. The primary file is services-config.xml that defines the channels, logging and other system configuration. The one change in this file is the URL of the standard AMF channel is changed to route requests through the Dispatcher Servlet:

<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
	<endpoint url="http://{server.name}:{server.port}/{context.root}/ 
				gorilla/messagebroker/amf"
			class="flex.messaging.endpoints.AMFEndpoint"/>

The web-application-config.xml file is the main configuration file. In fact once the other files are set-up this will often be the only file that you need to modify. In web-application-config.xml the MessageBrokerHandlerAdapter is declared so HTTP messges are routed to the Spring managed Message Broker.

<bean class="org.springframework.flex.messaging.servlet.MessageBrokerHandlerAdapter"/>

The other part of the framework that is declared in the file is the MessageBrokerFactoryBean. This bean maps the URL we want to handle, which is all requests sent to the Dispatch Servlet:

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<value>
			/*=mySpringManagedMessageBroker
		</value>
	</property>
</bean>


<bean id="mySpringManagedMessageBroker" class="org.springframework.flex.messaging.MessageBrokerFactoryBean"/>

Because the DispatcherServlet is listening on /gorilla, this configuration will pass all requests sent to the /gorilla URL to the Spring-managed MessageBroker. Then because message broker uses the channel configuration out of the WEB-INF/flex/services-config.xml, messages sent to /gorilla/messagebroker will be routed to the beans we declare as services.

So that the message broker nows about our beans, the next part of the configuration is the declaration of the applications Spring Beans and exporting them as remote services. In our example we declare the SodaService as a sodaBean:

<bean id="sodaBean" class="com.gorillalogic.sodaBank.SodaService"
		init-method="initSodaAccounts">
	<property name="numAccounts" value="1000"/>
</bean>/

Then the sodaBean is exposed for BlazeDS remoting:

<bean id="sodaService" class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
	<property name="messageBroker" ref="mySpringManagedMessageBroker"/>
	<property name="service" ref="sodaBean"/>
</bean>

This references the previous Message Broker bean to export the sodaBean. By default all of the methods on the class are exposed as a remote service. The FlexRemotingServiceExporter has a number of options that can configure the service. For example the methods that are exposed can be set using includeMethods and excludeMethods.

Setting up new Spring BlazeDS Integration Project - Client Side

The client side code for connecting to the server uses the standard Flex RemoteObjects. For the sample application we declare the following RemoteObject:

<mx:RemoteObject id="remoteObject" 
	destination="sodaService" 
	result="resultHandler(event);" 
	fault="faultHandler(event);"
	channelSet="{sodaChannels}"/> 


<mx:ChannelSet id="sodaChannels">
	<mx:AMFChannel uri="/gorilla/messagebroker/amf"/>
</mx:ChannelSet>   

This remote object allows the Flex Client to call the remote Java Server. To have the client know what channel to send the call on there are two options. The first is to compile the client against the server configuration file, services-config.xml. This is generally not an ideal solution, because it tightly couples the client to the server. Instead the channel is configured in the client with a channel set.

The call to the RemoteObject is similar to calling the object locally, the difference is the results come back asynchronously. For this reason a resultHandler is declared that is called when the results come back from the server. In the sample the call to the server is made as follows:

remoteObject.getSodaModel();

The results come back in a ResultEvent. These results are cast to our sodaModel:

sodaModel = event.result as SodaModel;

Securing the Remote Services - Server Side

To secure the communication with the server the Spring BlazeDS Integration project uses a custom authentication and authorization process. The process integrates Spring Security with the BlazeDS security process. (Note this uses code that at the time of writing was only available in the latest code checked out from SVN. The snapshot of the code we used for these samples is included as jar file).

The first part of configuring the security on the server is to define the security context. This defines the username, password and associated roles for the users. In this simple example we just define the users in the file. An enterprise project would probably want to authenticate against a database or using single-sign on.

To declare the users in the system we use a separate file, called security-context.xml. This file needs to be added to the Dispatcher Servlet context configuration so that it is loaded at startup. To do this we add the file to the configuration in web.xml to point to our file:

<servlet>
	<servlet-name>Spring MVC Dispatcher Servlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</ 
			servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/config/security-context.xml
			/WEB-INF/config/web-application-config.xml
		</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

Then in the security-context file we declare the system users:

<authentication-provider>
	<user-service>
	<user name="ryan" password="monkey" 
		authorities="ROLE_USER, ROLE_ADMIN" />
	<user name="alex" password="chimp" authorities="ROLE_USER" />
	</user-service>
</authentication-provider>

The second part of setting up the security on the server is to configure the message broker with the custom security configuration. To allow the Spring-managed message broker to be configured with additional services and/or security it allows additional configuration processors to be set on the MessageBrokerFactoryBean. The processors implement two methods, processBeforeStartup and processAfterStartup, which allow configuration to be set before or after startup of the message broker.

To configure the security of the message broker two processes are set. The first is the login command which provides authentication and authorization and the second is a security configuration processor, secures individual channels and URL's.

LoginCommand is the name of the interface in BlazeDS used to define the custom authentication and authorization process. The bean, SpringSecurityLoginCommand then integrates Spring Security with BlazeDS security, passing BlazeDS calls to authentication and authorization to the Spring managed security context. The following declares an instance of this bean, referencing the previously defined security context:

<bean id="loginCommand"
 		class="org.springframework.flex.messaging.security.SpringSecurityLoginCommand">
	<constructor-arg ref="_authenticationManager"/>
</bean>

The second process, a security configuration processor, is defined as a pointcut advisor that defines how individual channels and URL's are secured. A pointcut advisor is part of Spring AOP (aspect-oriented programming) that defines the advice that is called prior to the invocation of certain methods. What this essentially does is filter the calls to the remote services and blocks unauthorized calls.

Internally BlazeDS uses AMF Filters to perform pre and post processing on message invocations. These filters work similar to servlet filters and follow the standard pipe-and-filter design pattern. This allows an individual filter to stop processing of a message. The security process advices the AMF Filters of the channels to add Spring managed security.

To define the security processor, first we add two additional channels to the WEB-INF/flex/services-config.xml file:

<channel-definition id="my-protected-amf"
 					class="mx.messaging.channels.AMFChannel">
	<endpoint url="http://{server.name}:{server.port}/{context.root}/ 
 					gorilla/protected/messagebroker/amf"
			  class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
 

<channel-definition id="my-protected-by-id-amf"
  				class="mx.messaging.channels.AMFChannel">
	<endpoint url="http://{server.name}:{server.port}/{context.root}/
  					gorilla/protected2/messagebroker/amf"
			  class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

Next we define an endpoint source. This configures what endpoints or channels we want to secure and what roles can access them. For the sample we define a single role of user. We then configure one URL and one endpoint to secure:

<bean id="configAttribute"
 		class="org.springframework.security.ConfigAttributeDefinition">
	<constructor-arg type="java.lang.String" value="ROLE_USER"/>
</bean>
 

<bean id="endpointSource" 
 class="org.springframework.flex.messaging.security.EndpointDefinitionSource">
	<constructor-arg>
	    <bean class="org.springframework.security.util.AntUrlPathMatcher"/>
	</constructor-arg>
	<constructor-arg>
		<map>
			<entry>
				<key>
					<bean  class="org.springframework.security.intercept.web.RequestKey">
					<constructor-arg value="**/protected/
   							messagebroker/**"/>
					</bean>
				</key>
				<ref bean="configAttribute"/>
			</entry>
		</map>
	</constructor-arg>
	<constructor-arg>
		<map>
			<entry>
				<key>
					<value>my-protected-by-id-amf</value>
				</key>
				<ref bean="configAttribute"/>
			</entry>
		</map>
	</constructor-arg>
</bean>

This secures any channels which use the URL matching **/protected/messagebroker/**. In the sample this includes the my-protected-amf channel which listens on the /gorilla/protected/messagebroker/amf and the my-protected-by-id-amf channel.

Next we define the endpoint interceptor and exception translator to tie all of this configuration together:

<bean id="endpointInterceptor"

	  class="org.springframework.flex.messaging.security.EndpointServiceMessagePointcutAdvisor">
	<constructor-arg>
		<bean class="org.springframework.flex.messaging.security.EndpointInterceptor">
			<property name="accessDecisionManager" ref="_accessManager"/>
			<property name="authenticationManager" ref="_authenticationManager"/>
			<property name="objectDefinitionSource" ref="endpointSource"/>
		</bean>
	</constructor-arg>
</bean>

<bean id="exceptionTranslator" class="org.springframework.flex.messaging.security.EndpointServiceMessagePointcutAdvisor">
	<constructor-arg>
		<bean class="org.springframework.flex.messaging.security.SecurityExceptionTranslationAdvice"/>
	</constructor-arg>
</bean>

This configures the endpoint interceptor to apply the access and authentication managers on the endpoint sources.

And finally we change the definition of the Spring-managed message broker to use these configuration processors:

<bean id="mySpringManagedMessageBroker"
 class="org.springframework.flex.messaging.MessageBrokerFactoryBean">
<property name="configProcessors">
	<set>
		<ref bean="loginCommand"/>
		<ref bean="securityConfigProcessor"/>
	</set>
</property>
</bean>

This will cause the message broker to secure the channels defined in the endpoint interceptor with the security context we configured in the security-context.xml file. Now when we define our service, we also define the channels we want our service to communicate on.

<bean id="sodaService" class="org.springframework.flex.messaging.remoting.FlexRemotingServiceExporter">
	<property name="messageBroker" ref="mySpringManagedMessageBroker"/>
	<property name="service" ref="sodaBean"/>
	<property name="channelIds" value="my-protected-amf,
		my-protected-by-id-amf"/>
</bean>

For the soda service we have defined that it can only communicate over secure channels. This will block any calls to the service that are not from authenticated users in the correct role.

Securing the Remote Services - Client Side

Client side configuration of securing remote services is a much simpler process. All of the heavy lifting is done on the server side. On the client we change the remote object definition to include a secure channel:

<mx:RemoteObject id="remoteObject" 
	destination="sodaService" 
	result="resultHandler(event);" 
	fault="faultHandler(event);"
	channelSet="{sodaChannels}"/> 

<mx:ChannelSet id="sodaChannels">
	<mx:AMFChannel uri="/gorilla/protected/messagebroker/amf"/>
</mx:ChannelSet>   

Now the remote object has to be authenticated before we can make calls to the soda service. For example, if we did not authenticate and called the soda service to get the Soda Model the client would get the following error:

Received fault: [RPC Fault faultString="An Authentication object was not found in theB
SecurityContext" faultCode="Client.Authentication" faultDetail="null"]

To authenticate the client we simply pass login information to the channel set. An oversimplified example would be as follows:

var token:AsyncToken = sodaChannels.login(username.text, password.text);
token.addResponder(
	new AsyncResponder(
		function(result:ResultEvent, token:Object = null):void{
			remoteObject.getSodaModel(numAccounts.text);
		},
		function(result:FaultEvent, token:Object = null):void{
			ta.text += "Received fault: " + result.fault + "\n"; 
		}
	)
  );

This takes the login information from a username and password box and authenticates the user. Upon successful authentication the remote service is called, retrieving the Soda Model.

Summary

The Spring BlazeDS Integration project simplifies the development of Rich Internet Applications in Java by using the Spring development model. By providing integration with Spring Beans and Spring Security it simplifies exposing and securing Java classes as Remote Services directly to Flex clients. Overall this project will greatly aid in the development of Enterprise Applications with Flex, BlazeDS and Java.

Future releases of the Integration project will add further integration with Spring. Planned features include integration with further integration with Spring Security and JMS. There is also a planned a custom schema definition for defining the remote services on the server. This will greatly simplify the configuration files.

Hello stranger!

You need to Register an InfoQ account or to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

What about 'good old' SpringFactory & BlazeDS? by Jan Vissers

Hi,

I have the same question to you as I had for Christophe Coenraets on his article over here (ria.dzone.com/articles/introduction-spring-blaz...) at DZone. So basically - what does Spring/BlazeDS integration bring to the table extra compared to BlazeDS SpringFactory?

-J.

Re: What about 'good old' SpringFactory & BlazeDS? by Jeremy Grelle

The SpringFactory is fairly limited in its approach in that it relies on a 'dependency lookup' mechanism instead of making full use of Spring's DI facilities. This requires that any bean looked up and exposed by the SpringFactory must be available from a root WebApplicationContext, which in turn restricts your options for achieving good modularity in a complex application. Running the BlazeDS MessageBroker as a Spring-managed bean eliminates such restrictions and allows us to integrate with the AMF message processing pipeline on a deeper level. For example, the securing of BlazeDS Endpoints using Spring Security while providing proper handling and translation of results into AMF messages that have enough information to be reasoned upon in a useful way on the client would not be easy to achieve otherwise. In addition, we have been able to completely eliminate the need for writing and maintaining the BlazeDS-specific remoting-config.xml and messaging-config.xml files, and we have connected BlazeDS MessageDestinations to Spring JMS and Spring Integration facilities in ways that would not have been possible using the factory mechanism.

It must be pointed out that although this article has done an excellent job of illustrating the basic approach and architecture of Spring BlazeDS Integration, it looks to have been written using an early pre-M2 snapshot of the project's SVN trunk and is already rather outdated by the release last week of Spring BlazeDS Integration RC1. The configuration details (including both XML namespace support and annotation support) are significantly simpler than what is illustrated here, and the security and messaging features are now fully implemented. I would highly encourage anyone interested to check out Christophe Coenraets' latest version of the testdrive samples to get a full grasp of how much simpler things are with RC1. Look for these samples to be fully integrated into the project distribution and runnable out-of-the-box via Eclipse WTP in the upcoming RC2.

Jeremy Grelle
Spring BlazeDS Integration Lead

Testing by Kenny MacLeod

My big concern with using Blaze on the server is with testing. Specifically, how to write tests which invoke the blaze endpoints and verify they're behaving correctly, when it involves a proprietery binary protocol.

For this reason, I'm more inclined to stick with simple XML-over-HTTP endpoints and have my flex application talk to that instead. It's not as performant as Blaze, but and it's testable.

Re: What about 'good old' SpringFactory & BlazeDS? by pankaj pardasani

How Blazeds serializes the lazy beans / pojo's returned by hibernate under Spring environment? I guess blazeds still doesnt supports HibernateProxy and would fetch the whole object graph while doing the serialization for Flex/other RIA layer.

Re: What about 'good old' SpringFactory & BlazeDS? by Jeremy Grelle

That's correct, BlazeDS doesn't have any out-of-the-box support for handling Hibernate lazy associations. But there are a number of open source adapters that can be plugged in to handle this, such as dpHibernate and Gilead.

Re: Testing by Adelino Rodrigues

I agree that using XML messages over http makes it simple to test and develop the Flex code independently from the backend.

Achieving the same degree of decoupling with Remote Object calls is harder... but achievable. We managed to get this degree of decoupling by using:

  • Spring for Action Script (Prana framework) for being able to configure the Remote Object implementation from the flex side

  • By providing mock implementations for all our Remote Object implementations


This way our Flex developers can work autonomously from FlexBuilder, do debugging, etc without having to connect to a backend.

Re: What about 'good old' SpringFactory & BlazeDS? by Wim Deblauwe

We just switched from SpringFactory to the Spring-BlazeDS integration and configuration is significantly simpler. We also had a special layer to define what methods in our server can be called by the Flex client, but this is now no longer needed as this can be configured via Spring BlazeDS.

BlazeDs vs GraniteDS by Kenny MacLeod

How does BlazeDS compare with GraniteDS? The latter seems to be an open-source reimplementation of much that Blaze does, with many bells and whistles on top, such as runtime generation of AS3 and MXML from a web container.

Sounds too good be true, though.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

8 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2013 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT