Showing posts with label flex. Show all posts
Showing posts with label flex. Show all posts

Saturday, February 4, 2012

Browser cache, Flex and Maven

A current issue with web application, is the browser cache.

For usual HTML based application, add some meta data is enough:

<meta equiv="CACHE-CONTROL" content="NO-CACHE">
<meta http-equiv="EXPIRES" content="Mon, 01 Jan 1970 00:00:01 GMT">

But with Flex application, it is not so simple.

Flex application are usually wrapped in HTML that allows to detect with the right Flash Player is installed. And if it is not the case, downloading and installing it.

The issue is the Flex SWF name that is specified in the HTML wrapper, makes that browsers put Flex application in cache and don’t reload it.

In the following explanations, the example is a Maven project with a module for the Flex application (using FlexMojos), and a module for the web application.

In the Flex module, the produced SWF file name must be variable, for example, by adding the current version. It is done by giving the final name of the SWF.

In build section, provide the finalName:

<project >
<groupId>my.app</groupId>
<artifactId>myapp-flex-client</artifactId>
<packaging>swf</packaging>
<build>
<finalName>MyFlexApp-${parent.version}</finalName>
<sourceDirectory>src/main/flex</sourceDirectory>
<testSourceDirectory>src/test/flex</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.sonatype.flexmojos</groupId>
<artifactId>flexmojos-maven-plugin</artifactId>
<configuration>
<sourceFile>MyApplication.mxml</sourceFile>
</configuration>
</plugin>
</plugins>
</build>

In the web application, we have to inject the SWF name in the HTML wrapper.

It is done by adding the wrapper goal to Flexmojos plugin.

<groupId>org.sonatype.flexmojos</groupId>
<artifactId>flexmojos-maven-plugin</artifactId>
<version>${flex.mojos.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>wrapper</goal>
<goal>copy-flex-resources</goal>
</goals>
</execution>
</executions>

Adding it, implies to configure it directly in the plugin. The configuration must contains the artefact to wrap (the Flex application) and the name of the wrapper.

<configuration>
<wrapperArtifact>
<groupId>my.app</groupId>
<artifactId>myapp-flex-client</artifactId>
</wrapperArtifact>
<swf>{build.finalName}</swf>
<htmlName>flashClientWrapper.html</htmlName>
</configuration>

The element defines a variable that is injected in the HTML file. Now, it only remains replace the SWF file name in the wrapper by: ${swf}

Friday, July 16, 2010

Flexmojos et les charts

Une configuration standard du plugin Flexmojos ne permet pas de compiler des charts. La compilation renvoie l'erreur suivante:

[ERROR] Could not resolve <mx:linechart> to a component implementation.

Les dépendances nécessaires ne sont pas disponibles sur un repo Maven. Il faut les ajouter dans le repo local à partir d'une installation du SDK Flex.

Pour commencer, il faut ajouter les dépendances dans le fichier Maven:

<dependency>
<groupid>com.adobe.flex.sdk</groupid>
<artifactid>datavisualization</artifactid>
<type>swc</type>
<scope>merged</scope>
<version>3.2.0.3958</version>
</dependency>
<dependency>
<groupid>com.adobe.flex.sdk</groupid>
<artifactid>datavisualization</artifactid>
<version>3.2.0.3958</version>
<type>rb.swc</type>
<classifier>en_US</classifier>
</dependency>

La seconde dépendances permet d'éviter l'erreur de compilation:

Unable to resolve resource bundle "charts" for locale "en_US".

Ensuite, il faut rajouter les dépendances dans le repo Maven local:

mvn install:install-file -DgroupId=com.adobe.flex.sdk
-DartifactId=datavisualization
-Dversion=3.2.0.3958
-Dpackaging=swc
-Dfile="/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/libs/datavisualization.swc"

Ensuite, il faut rajouter le ressource bundle:

mvn install:install-file -DgroupId=com.adobe.flex.sdk
-DartifactId=datavisualization
-Dversion=3.2.0.3958
-Dclassifier=en_US
-Dpackaging=rb.swc
-Dfile="/Applications/Adobe Flex Builder 3/sdks/3.2.0/frameworks/local/locale/en_US/datavisualization_rb.swc"

Si le scope de l'artifact datavisualization n'est pas mis à merge, l'application compilera, mais l'erreur suivante arrivera à l'exécution:

VerifyError: Error #1014: Class mx.charts::LineChart could not be found.

Il reste encore un problème à résoudre: la licence. Avec la configuration actuelle, les charts vont être affichés avec le message: Trial Visualization.

Il faut configurer le pom pour qu'il utilise la licence à la compilation:

<build>
<sourcedirectory>src/main/flex</sourcedirectory>
<plugins>
<plugin>
<groupid>org.sonatype.flexmojos</groupid>
<artifactid>flexmojos-maven-plugin</artifactid>
<version>3.5.0</version>
<extensions>true</extensions>
<configuration>
<contextroot>/appcontext</contextroot>
<debug>true</debug>
<licenses>
<flexbuilder3>nnnn-nnnn-nnnn-nnnn-nnnn-nnnn</flexbuilder3>
</licenses>
<sourcefile>App.mxml</sourcefile>
<targetplayer>9.0.124</targetplayer>
</configuration>
<dependencies>
<dependency>
<groupid>com.adobe.flex</groupid>
<artifactid>license</artifactid>
<type>jar</type>
<version>3.2.0.3958</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

La dépendance ne doit être rajouté qu'au plugin, pas au projet.

Le jar nécessaire à la licence n'est pas disponible non plus sur un repo maven, il faut donc l'installer à partir d'une installation Flex avec la commande suivante:

mvn install:install-file
-DgroupId=com.adobe.flex
-DartifactId=license
-Dversion=3.2.0.3958
-Dpackaging=jar
-Dfile="C:\Program Files\Adobe\Flex Builder 3 Plug-in\sdks\3.2.0\lib\license.jar"

Aprés une compilation, les charts s'afficheront sans le message de trial.

Intégration Spring Flex

Spring Source a présenté l'année dernière à SpringOne, son projet d'intégration Spring et Flex, Spring Flex. Ce projet veut simplifier la mise en place d'un backend Spring derrière BlazeDS, le message broker free de Adobe. L'exemple suivant décrit les fichiers de nécessaires pour une configuration standard avec des Remote Object.

Fichier Maven

Le plugin utilisé pour compiler Flex est FlexMojos.
Sans passer par l'intégration de Spring Flex, il faut déclarer chaque jar BlazeDS comme dépendance, ce qui fait une demi douzaine de dépendances au total, Adobe n'ayant pas géré les dépendances entre les modules de BlazeDS.
Le fichier Maven de Spring Flex référence tous les modules nécessaires de BlazeDS.

<dependency>
<groupid>org.springframework.flex</groupid>
<artifactid>spring-flex</artifactid>
<version>1.0.3.RELEASE</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>

Cette version de Spring Flex est dépendante de la version 2.5.6 de Spring.

Structure du WAR

L'application est configurée pour utiliser les répertoires suivant sous le répertoire WEB-INF:
  • conf: configuration SpringFlex
  • flex: configuration BlazeDS
  • spring: configuration vers le backend

Déclaration dans le fichier web.xml

La configuration de Spring se fait en utilisant les fonctionnalités de Spring MVC. Le chargement du context Spring se fait en déclarant les contextes du backend a charger et le listener de chargement.

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/*-context.xml
</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Ensuite, le DispatcherServlet est déclarer pour matcher toutes les requêtes vers le message broker. Il doit être initialisé avec un fichier de contexte Spring configurant l'intégration SpringFlex.

<servlet>
<servlet-name>flex</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>
</servlet>

<servlet-mapping>
<servlet-name>flex</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>

Configuration de BlazeDS

La configuration de BlazeDS passe par le fichier de contexte Spring utilisé par le DispatcherServlet: /WEB-INF/config/web-application-config.xml. Il ne fait que déclarer la configuration du message broker. Dans notre cas, la configuration par défaut est suffisante.
Le message broker est configurer pour charger le fichier de configuration des services BlazeDS
dans: WEB-INF/flex/services-config.xml.

<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">

<flex:message-broker/>

</beans>

C'est dans ce fichier que l'on pourra déclarer les Remote Object.

Le fichier des services BlazeDS est réduit au minimal pour une configuration standard. Dans notre cas, il n'est pas nécessaire d'avoir d'autres fichiers de configuration.
Il suffit de déclarer le channel par défaut et de le configurer.

<services-config>

<services>
<default-channels>
<channel ref="my-amf">
</default-channels>
</services>

<channels>
<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>
</channels>
</services-config>

Déclaration des Remote Object

SpringFlex offre deux façons de déclarer des Remote Object:
  • Par configuration
  • Par annotation

Par configuration

Le namespace flex apporte l'élément remoting-destination qui permet de référencer un bean Spring et de l'exposer comme Remote Object. L'attribut ref permet de référencer un bean par son id. Et l'attribut destination-id permet de déclarer le nom du Remote Object coté Flex. Par défaut, destination-id est égale à l'id du bean.

<flex:remoting-destination id="userService" ref="userService"/>

Par annotation

L'annotation RemotingDestination de SpringFlex permet de déclarer au niveau de la classe d'un bean, qu'il doit être exposé à Flex via le message broker. Elle permet également de déclarer la destination, mais par défaut, il s'agira du nom du bean avec la première lettre en minuscule.
Cet approche couple directement les beans du backend à la technologie du frontend, ce qui, dans le cas d'un changement de technologie web, obligera les développeurs à garder des dépendances inutiles.