mercredi 4 novembre 2009

New in GraniteDS 2.1.0 RC1: simplified configuration for Seam and Spring

Hi all,

Starting a new Flex + GraniteDS + Seam/Spring project or 'granitizing' an existing project is not a very complex task but involves quite a few configuration files and makes hard to get started for new users.

Following the releases of the Spring-BlazeDS project and the beginning of the Seam-BlazeDS integration, we have implemented a similar mechanism that in most cases requires only one line of specific server configuration for GraniteDS.

Let's start by Seam :

The setup of a Seam + GraniteDS project used to require changes or additions of web.xml, components.xml, granite-config.xml and services-config.xml.

With GDS 2.1, all you need is to add the GDS libraries in WEB-INF/lib or ear/lib and modify components.xml :

<components xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
xmlns:security="http://jboss.com/products/seam/security"
xmlns:transaction="http://jboss.com/products/seam/transaction"
xmlns:persistence="http://jboss.com/products/seam/persistence"
xmlns:framework="http://jboss.com/products/seam/framework"
xmlns:bpm="http://jboss.com/products/seam/bpm"
xmlns:jms="http://jboss.com/products/seam/jms"
xmlns:web="http://jboss.com/products/seam/web"
xmlns:graniteds="http://www.graniteds.org/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
http://jboss.com/products/seam/transaction http://jboss.com/products/seam/transaction-2.0.xsd
http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.0.xsd
http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.0.xsd
http://jboss.com/products/seam/jms http://jboss.com/products/seam/jms-2.0.xsd
http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.0.xsd
http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.0.xsd
http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd
http://jboss.com/products/seam/framework http://jboss.com/products/seam/framework-2.0.xsd
http://www.graniteds.org/config http://www.graniteds.org/config/granite-config-2.1.xsd">


<core:init jndi-pattern="myapp/#{ejbName}/local" debug="true"/>

<core:manager concurrent-request-timeout="500"
conversation-timeout="120000" conversation-id-parameter="cid" parent-conversation-id-parameter="pid"/>

<persistence:entity-manager-factory name="ejb3" persistence-unit-name="ejb3"/>

<persistence:managed-persistence-context name="entityManager" entity-manager-factory="#{ejb3}"/>

<security:identity jaas-config-name="other"/>


<graniteds:flex-filter url-pattern="/graniteamf/*" tide="true"/>

</components>

The important part is the flex-filter declaration. It allows to map an url-pattern (in most cases /graniteamf/* is a good default value) to the GraniteDS AMF request processor. The attribute tide="true" defines a Tide/Seam service factory, otherwise this will be a simple Seam service factory.
This configuration assumes that the Seam filter is mapped in web.xml to /*, which is the case for Seam projects generated by seam-gen or by the Eclipse Seam tools.

Note that if you need to use Gravity, you still will have to declare manually the Gravity servlet in web.xml and change the filter mapping for SeamFilter. This is because the declaration depends on the servlet container and SeamFilter cannot be used with most container comet implementations (in particular Tomcat 6 CometProcessor).


Now Spring :

No big surprise, this is almost exactly the same for Spring, except of course that this time it assumes that a Spring MVC DispatcherServlet is mapped, so there is still some changes in web.xml if you don't have one :

web.xml :
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/graniteamf/*</url-pattern>
</servlet-mapping>

applicationContext.xml :
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:graniteds="http://www.graniteds.org/config"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.graniteds.org/config http://www.graniteds.org/config/granite-config-2.1.xsd">

<context:component-scan base-package="com.myapp.service" />

<tx:annotation-driven transaction-manager="transactionManager"/>

...

<graniteds:flex-filter url-pattern="/*" tide="true"/>

</beans>

The configuration is very similar to the one for Seam, except that the url-pattern is this time relative to the url-mapping of the Spring DispatcherServlet. This is also very similar to the configuration for Spring-BlazeDS.

It is also possible to share an existing DispatcherServlet between a Web/Spring MVC and a GraniteDS/Flex front-ends, only the Flex channel endpoint url will be different (for example http://myserver/myapp/spring/graniteamf/amf instead of http://myserver/myapp/graniteamf/amf).


In these two new configurations, there is no need for services-config.xml or granite-config.xml, however you can add one for more detailed configuration options.


The absence of service-config.xml means that the RemoteObject channels can not be defined during the compilation of the Flex application. That means that it will be necessary to provide them manually :

<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns="*"
xmlns:cs="test.granite.components.*"
layout="vertical"
backgroundGradientColors="[#0e2e7d, #6479ab]"
preinitialize="preinit()">

<mx:Script>
<![CDATA[
private var graniteChannelSet:ChannelSet;

private function preinit():void {
Spring.getInstance().initApplication();

graniteChannelSet = new ChannelSet();
graniteChannelSet.addChannel(new AMFChannel("graniteamf", "http://{server.name}:{server.port}/myapp/graniteamf/amf"));

Spring.getInstance().remoteObjectInitializer = function(ro:RemoteObject):void {
ro.channelSet = graniteChannelSet;
};

}
]]>
</mx:Script>
...
</mx:Application>

This a bit more complex that simply using services-config.xml, but that also means that you can dynamically configure the channel set, for example using the technique described here.


This new Seam/Spring configuration can handle a few options that were only in granite-config.xml before :

<graniteds:flex-filter url-pattern="/*" tide="true">
<graniteds:tide-annotations>
<graniteds:value>org.springframework.stereotype.Controller</graniteds:value>
</graniteds:tide-annotations>
<graniteds:exception-converters>
<graniteds:value>com.myapp.util.MyExceptionConverter</graniteds:value>
</graniteds:exception-converters>
</graniteds:flex-filter>


Messaging destinations that were previously declared in services-config.xml can now also be declared in components.xml or applicationContext.xml :

Simple messaging destination :
<graniteds:messaging-destination 
name="addressBookTopicDestination"
id="addressBookTopic"
no-local="true"
session-selector="true"/>


JMS topic destination :
<graniteds:jms-topic-destination id="addressBookTopic"
name="dataTopic"
connection-factory="ConnectionFactory"
jndi-name="topic/testTopic"
acknowledge-mode="AUTO_ACKNOWLEDGE"
transacted-sessions="true"
no-local="true"
session-selector="true"/>



Hopefully these new configuration options will make easier for new users to get started with GraniteDS and maybe for Spring-BlazeDS users to easily switch to GraniteDS if they want to.

2 commentaires:

Anonyme a dit…

I think this is because the declaration depends on the servlet container and SeamFilter cannot be used with most container comet implementations.
Kitchen Islands

Anonyme a dit…

Great, thanks for give the scripts