Spring BlazeDS Integration et rappel sur BlazeDS
Par Romain MALLARD, vendredi 12 février 2010 à 21:39 :: Java :: #128 :: rss

BlazeDS est un projet open source d'Adobe permettant de connecter un front-end Flex à des services dans un back-end Java. Par défaut BlazeDS ne supporte pas les services gérés par Spring mais il est possible de le faire en utilisant une factory qui va faire le lien entre BlazeDS et Spring mais ce qui implique de faire un fichier de configuration BlazeDS séparé.
Le projet Spring BlazeDS Integration a été initié afin de simplifier les choses en faisant du MessageBroker un objet géré par Spring, ce qui ouvre la voie à une intégration plus poussée dans l'esprit Spring.
2.Utilisation de Spring BlazeDS Integration
La configuration de HttpFlexSession dans le fichier web.xml ne change pas et le ContextLoaderListener est forcément présent car on utilise Spring :
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Le composant central à configurer pour utiliser Spring BlazeDS Integration est le MessageBroker. Les messages HTTP du client Flex vont être routés à travers la servlet DispatcherServlet (de Spring) vers le MessageBroker (géré par Spring).
Dans une application BlazeDS classique, les 3 fichiers messaging-config.xml, proxy-config.xml et remoting-config.xml sont des fichiers de configuration qui sont référencés comme service-include dans le fichier services-config.xml et ce fichier est spécifié dans la déclaration de la servlet MessageBrokerServlet dans le fichier web.xml.
Avec l'utilisation de Spring BlazeDS Integration, la définition des services de type MessageService, HTTPProxyService et RemotingService peut se faire d'une autre manière dans les fichiers de configuration Spring.
Contrairement aux services cités ci-dessus, les channel-definition n'ont pas de tag équivalent dans Spring BlazeDS Integration, ils sont toujours dans le fichier services-config.xml. Les tags de la configuration Spring BlazeDS Integration sont disponibles sous le namespace flex :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:flex="http://www.springframework.org/schema/flex" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/flex http://www.springframework.org/schema/flex/spring-flex-1.0.xsd"> ... </beans>
La déclaration <flex:message-broker/> dans le fichier de contexte Spring web-application-config.xml va configurer automatiquement un ensemble d'éléments :
- le MessageBrokerFactoryBean déclaré comme un bean dans le contexte Spring
- un MessageBrokerHandlerAdapter et un HandlerMapping approprié (en l'occurrence un SimpleUrlHandlerMapping) pour router les requêtes entrantes vers le MessageBroker (géré par Spring).
3. Retour sur l'architecture BlazeDS
3.1. Architecture générale

Le client Flex fait une requête au serveur sur un channel et la requête est routée vers un endpoint sur le serveur BlazeDS. Du endpoint une requête est ensuite routée à travers une chaîne d'objets (java) qui inclut l'objet MessageBroker, un objet service, un objet destination et finalement un objet adaptateur qui réalise la requête localement ou en contactant un back-end ou un serveur distant comme un serveur JMS.
Les channels coté client et les endpoint coté serveur doivent avoir le même format de message.
Quand un endpoint a traité la requête, il extrait le message à l'intérieur de la requête et le donne au MessageBroker qui va inspecter sa destination et va passer le message au service attendu.
Les adaptateurs sont le dernier maillon dans la chaîne de traitement des messages.
BlazeDS est fourni avec un ensemble de adaptateurs pour communiquer avec des services différents mais il est possible d'utiliser des adaptateurs personnalisés.
Voici les liens entre les composants coté client et les services BlazeDS :
- HTTPService et WebService communiquant avec HTTPProxyService / HTTPProxyDestination
- RemoteObject communiquant avec RemotingService / RemotingDestination
- Producer et Consumer communiquant avec MessageService / MessageDestination

3.2. Architecture Message Service
Le Message Service est basé sur un modèle publisher/subscriber, il agit comme un routeur de message entre clients Flex ou entre clients supportant JMS ou les 2.

BlazeDS propose un ensemble de type de channel :
- polling simple
- polling long (presque du temps-réel)
- streaming temps-reel
BlazeDS ne supporte pas le RTMP (Real Time Messaging Protocol) contrairement à la solution commerciale LiveCycle Data Services.
3.2.1. Le polling simple
Dans le cas du polling simple, le client "ping" le serveur à intervalle régulier et un acquittement vide est retourné pour indiquer qu'il n'y a pas de message pour le client.

Voici un exemple de configuration BlazeDS :
<services-config>
...
<channels>
...
<channel-definition id="my-polling-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint
url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling"
class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>4</polling-interval-seconds>
</properties>
</channel-definition>
...
3.2.2. Le polling long
Ce polling est un peu différente du polling simple. Au lieu d'acquitter tout de suite, le serveur garde la requête de polling jusqu'à ce qu'il y a un message pour le client. Cela assure que les messages soient envoyés au client dés qu'ils sont disponibles.

Voici un exemple de configuration BlazeDS :
<services-config>
...
<channels>
...
<channel-definition id="my-polling-amf"
class="mx.messaging.channels.AMFChannel">
<endpoint
url="http://{server.name}:{server.port}/{context.root}/messagebroker/amfpolling"
''class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>true</polling-enabled>
<polling-interval-seconds>4</polling-interval-seconds>
</properties>
</channel-definition>
...
3.2.3. Le streaming temps-réel
BlazeDS supporte le streaming temps-réel sur des channels AMF et HTTP. Contrairement au polling long qui ferme et réouvre une connexion sur réception d'un message, le streaming garde la connexion ouverte tout le temps.

Voici un exemple de configuration BlazeDS :
<services-config>
...
<channels>
...
<channel-definition id="my-streaming-amf"
class="mx.messaging.channels.StreamingAMFChannel">
<endpoint
url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamingamf"
class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
</channel-definition>
...
4. Utilisation du service Remoting
4.1. Configuration avec Spring sans l'aide de Spring BlazeDS Integration
Avant Spring BlazeDS Integration, il fallait :
- définir une factory dans le fichier services-configuration.xml car le comportement standard de BlazeDS est de localiser les instances du service sans passer par Spring, cette factory charge d'interroger le contexte Spring.
<services-config>
<factories>
<factory id="SpringFactory" class="com.myexample.web.SpringFactory" />
</factories>
...
- définir le service dans le fichier remoting-service.xml en précisant pour la destination la factory Spring et la source
<service id="remoting-service" class="flex.messaging.services.RemotingService">
<adapters>
<adapter-definition id="java-object"
class="flex.messaging.services.remoting.adapters.JavaAdapter"
default="true"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
<destination id="exampleServiceDest">
<properties>
<source>exampleServiceBean</source>
<factory>SpringFactory</factory>
</properties>
</destination>
</service>
- définir aussi le service dans le fichier de contexte Spring :
<bean id="exampleServiceBean" class="com.myexample.service.ExampleService"/>
- la configuration des channel doit être précisée dans le fichier services-configuration.xml :
...
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint
url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
...
4.2. Configuration avec l'aide de Spring BlazeDS Integration
Avec l'utilisation de Spring BlazeDS Integration, la configuration est plus simple car en déclarant les lignes suivantes dans les fichiers de configuration Spring on arrive au même résultat :
<flex:message-broker/>
<flex:remoting-destination ref="exampleService" />
<bean id="exampleService" class="com.myexample.service.ExampleService"/>''
La configuration des channel située dans le fichier services-configuration.xml ne change pas.
A noter que la ligne <flex:remoting-destination ref="exampleService" /> va configurer la destination avec comme id la valeur de ref, le client Flex précisera cet id comme destination.
Il est possible de préciser les channels par défaut par la déclaration suivante :
<flex:message-broker>
<flex:remoting-service default-adapter-id="my-default-remoting-adapter"
default-channels="my-amf, my-secure-amf" />
</flex:message-broker>
Il existe une autre manière de déclarer les services en une fois :
<bean id="exempleService" class="com.myexample.ExampleService" > <flex:remoting-destination /> </bean>
au lieu de :
<flex:remoting-destination ref="exampleService" /> <bean id="exampleService" class="com.myexample.service.ExampleService"/>
Les annotations dans les classes Java permettent de configurer les services sans avoir besoin de déclarer la configuration flex:remoting-destination :
package com.myexample.product;
import org.springframework.flex.remoting.RemotingDestination;
import org.springframework.flex.remoting.RemotingExclude;
import org.springframework.flex.remoting.RemotingInclude;
import org.springframework.stereotype.Service;
@Service("exampleService")
@RemotingDestination(channels={"my-amf","my-secure-amf"})
public class ExampleServiceImpl implements ExampleService {
@RemotingInclude
public Product read(String id) {...}
@RemotingExclude
public Product create(Product product) {...}
@RemotingInclude
public Product update(Product product) {...}
@RemotingExclude
public void delete(Product product) {...}
}
5. Utilisation du service Messaging
5.1. Service Messaging sans destination précisée
5.1.1. Configuration sans Spring
Voici un exemple avec des valeurs par défaut :
<service id="remoting-service"
class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript"
class="flex.messaging.services.messaging.adapters.ActionScriptAdapter"
default="true"/>
</adapters>
<default-channels>
<channel ref="my-polling-amf"/>
</default-channels>
</service>
5.1.2. Configuration avec l'aide de Spring BlazeDS Integration
La configuration est simplifiée et se résume à :
<flex:message-broker/>
Dans le cas où une configuration particulière doit être appliquée sur le message-service, le tag flex:message-service doit être appliqué :
<flex:message-broker>
<flex:message-service default-adapter-id="my-default-messaging-adapter"
default-channels="my-polling-amf" />
</flex:message-broker>
5.2. Service Messaging avec destination précisée
5.2.1. Configuration sans Spring
Voici la configurer à suivre :
- définir les services Messaging dans le fichier messaging-configuration.xml
<service id="message-service"
class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript"
class="flex.messaging.services.messaging.adapters.ActionScriptAdapter"
default="true"/>
</adapters>
<destination id="chat-application">
...
<adapter ref="actionscript"/>
...
<channels>
<channel ref="my-polling-amf"/>
</channels>
...
<properties>
<network>
<session-timeout>0</session-timeout>
<throttle-inbound policy="ERROR" max-frequency="50"/>
<throttle-outbound policy="REPLACE" max-frequency="500"/>
</network>
<server>
<max-cache-size>1000</max-cache-size>
<message-time-to-live>0</message-time-to-live>
<durable>true</durable>
<durable-store-manager>flex.messaging.durability.FileStoreManager
</durable-store-manager>
</server>
</properties>
</destination>
</service>
5.2.2. Configuration avec l'aide de Spring BlazeDS Integration
La configuration est simplifiée et se résume à :
<flex:message-broker id="chat-application"/>
5.3. Utilisation du service Messaging JMS
5.3.1.Configuration sans l'aide de Spring BlazeDS Integration
Voici la configurer à suivre :
- déclarer des ressources pour la gestion de topic dans le fichier context.xml de l'application :
<Context path="/BlazeTest">
<Resource name="jms/flex/TopicConnectionFactory"
type="org.apache.activemq.ActiveMQConnectionFactory"
description="JMS Connection Factory"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
brokerURL="tcp://localhost:61616"
brokerName="myBroker"/>
<Resource name="jms/messageTopic"
type="org.apache.activemq.command.ActiveMQTopic"
description="a simple topic"
factory="org.apache.activemq.jndi.JNDIReferenceFactory"
physicalName="messageTopic"/>
</Context>
- déclarer les services dans les fichiers de configuration Spring :
<service id="message-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="jms"
class="flex.messaging.services.messaging.adapters.JMSAdapter"
default="true"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
<destination id="chat-topic-jms">
<properties>
...
<jms>
<destination-type>Topic</destination-type>
<message-type>javax.jms.TextMessage</message-type>
<connection-factory>jms/flex/TopicConnectionFactory</connection-factory>
<destination-jndi-name>jms/topic/flex/simpletopic</destination-jndi-name>
<delivery-mode>NON_PERSISTENT</delivery-mode>
<message-priority>DEFAULT_PRIORITY</message-priority>
<acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
</jms>
</properties>
...
<adapter ref="jms"/>
</destination>
5.3.2. Configuration avec l'aide de Spring BlazeDS Integration
Voici la configurer à suivre :
- spécifier une référence connectionFactory JMS (elle est requise mais n'est pas explicitement spécifié si il y en a déja une de configuré dans le contexte de l'application avec un id "connectionFactory") :
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616"/> </bean>
- configurer un bean "chatInQueue"
<bean id="chatInQueue" class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg value="queue.flex.chat.in"/> </bean> ...
- utiliser le tag jms-message-destination pour exposer une destination JMS comme un message destination BlazeDS :
<flex:jms-message-destination id="chatIn" jms-destination="chatInQueue" />
5.4. Configuration IntegrationAdapter avec Spring BlazeDS Integration
Pour router des messages avec Spring BlazeDS Integration, un IntegrationAdapter est disponible pour envoyer/recevoir des messages via un MessageChannel, ce qui est utile pour se connecter à un endpoint Email ou FTP. Le tag integration-message-destination est utilisé pour exposer le MessageChannel comme un message destination BlazeDS.
L'exemple suivant configure un message destination "chatOut" utilisant le PublishSubscribeChannel "chatOutPubSubChannel" :
<integration:publish-subscribe-channel id="chatOutPubSubChannel" />
<flex:integration-message-destination id="chatOut"
message-channel="chatOutPubSubChannel" />
A Noter que le tag integration:publish-subscribe-channel fait partie de Spring Integration et non de Spring BlazeDS integration.
5.4. Configuration MessageTemplate avec Spring BlazeDS Integration
Voici un exemple d'utilisation de la classe MessageTemplate avec 2 classes d'exemples :
- configuration du bean defaultMessageTemplate dans les fichiers de configuration Spring :
<bean id="defaultMessageTemplate" class="org.springframework.flex.messaging.MessageTemplate" />
- configuration du bean POJO "feed1Starter" dans les fichiers de configuration Spring :
<bean id="feed1Starter"
class="com.myexample.Feed1">
<constructor-arg ref="defaultMessageTemplate" />
<flex:remoting-destination />
</bean>
- configuration d'une destination feed1 dans les fichiers de configuration Spring :
<flex:message-destination id="feed1" />
- création de la classe POJO "Feed1" lançant un thread qui utilise le MessageTemplate en appelant sa méthode send(String destination, Object body) avec comme destination "feed1" et comme body le contenu du message.
- configuration du bean POJO "feed1Starter" dans les fichiers de configuration Spring :
<bean id="feed2Starter"
class="com.myexample.Feed2">
<constructor-arg ref="defaultMessageTemplate" />
<flex:remoting-destination />
</bean>
- configuration d'une destination feed2 dans les fichiers de configuration Spring :
<flex:message-destination id="feed2"
allow-subtopics="true" subtopic-separator="." />
- création de la classe POJO "Feed2" lançant un thread qui utilise le MessageTemplate en appelant sa méthode send(AsyncMessageCreator creator) de la façon suivante :
template.send(new AsyncMessageCreator() {
public AsyncMessage createMessage() {
AsyncMessage msg =
template.createMessageForDestination("feed2");
msg.setHeader("DSSubtopic", content);
msg.setBody(stock);
return msg;
}
});
6. Service HTTPProxy
Spring BlazeDS Integration n'apporte pas de simplifications en ce qui concerne les services HTTPProxy. Ils sont déclarés de la même façon :
- inclusion du fichier proxy-config.xml dans le fichier services-config.xml
<services-config>
<services>
...
<service-include file-path="proxy-config.xml" />
</services>
...
- déclaration des services HTTProxy dans le fichier proxy-config.xml
<service id="proxy-service" class="flex.messaging.services.HTTPProxyService">
<!-- Define channels and destinations. -->
<properties>
<connection-manager>
<max-total-connections>100</max-total-connections>
<default-max-connections-per-host>2</default-max-connections-per-host>
</connection-manager>
<!-- Allow self-signed certificates. Do not use in production -->
<allow-lax-ssl>true</allow-lax-ssl>
<!-- Connection settings for an external proxy. -->
<external-proxy>
<server>10.10.10.10</server>
<port>3128</port>
<nt-domain>mycompany</nt-domain>
<username>flex</username>
<password>flex</password>
</external-proxy>
</properties>
</service>
7. Sources d'information
Using Spring BlazeDS Integration 1.0

Commentaires
1. Le jeudi 9 septembre 2010 à 07:42, par Lotfus
Ajouter un commentaire