Home >
Anatomy of an Enterprise Flex RIA Part 7: The ui Project Maven Build
In the web project, Maven will compile any Java classes during the compilation phase of the build. That’s a great time to build the Flex project as well, so we’ll have Ant do that. Here’s what we need to get Ant to compile Flex:
<project default="compile-flex" basedir="." name="Bookie MXML Tasks">
<property file="${user.home}/.m2/maven.properties"/>
<property name="maven.repo.local" value="${user.home}/.m2/repository"/>
<property file="mxml.project.properties" />
<property file="cairngen.properties" />
<!-- cairngen configuration properties -->
<property file="config/cairngen.properties" />
<property file="config/log.properties" />
<property name="war.src.dir" location="src/main/bookie.war"/>
<property name="war.build.dir" location="target/bookie"/>
<property location="src/main/flex" name="src.dir" />
<property location="target/bookie" name="build.dir" />
<property location="src/main/bookie.war/WEB-INF/flex/flex-config.xml" name="flex.config" /> <property location="src/main/bookie.war/WEB-INF/flex/services-config.xml" name="services.config" />
<path id="maven.repo.classpath">
<fileset dir="${maven.repo.local}">
<includename="com/adobe/ac/ant/tasks/FlexAntTasks/1.0/FlexAntTasks-1.0.jar"
/> </fileset>
</path>
<taskdef name="flexunit" classname="com.adobe.ac.ant.tasks.FlexUnitTask">
<classpath>
<path refid="maven.repo.classpath"/>
</classpath>
</taskdef>
Last, we define a task called flexunit so that we can call the FlexUnit tests during the Maven test phase.
We’ll compile the .swfs that are created from the Flex applications to the same directory where Maven builds Java files. We’ll do this for consistency, but also because we’ll have Eclipse/Flex Builder compile .swfs to that build directory as well; the copy tasks will work with the .swfs that end up there no matter which application compiled them. That way, Eclipse/Flex Builder can run a copy task after a project build to make it easy to review changes by using an “external builder."
First, right-click the build file in the Eclipse navigator and select External Tools, as shown in Figure 6.
Then, click the New button in the top left, change the name to something that makes sense (I chose bookie-ui build.xml), and click the Targets tab, as shown in Figure 7.
Change the executed target to copy-changes, click Apply, and then click Close (see Figure 8).
Now whenever the project is built and the Flex source is compiled into .swf files, the copy-changes target is run and the changed web files, including .swfs, are copied to the deploy directory.
Speaking of compiling, here’s a sample Flex compilation task in Ant. In this example, I use Ant to execute a system call to the Flex compiler. I could have gone with Adobe’s excellent Ant tasks for working with the mxml compiler (Flex Ant Tasks at Adobe), but that would have required one more JAR to get into Maven or check into source control. Because the use case is not that complicated, I stuck with just making a system call with the exec tag.
This task is for compiling the index application, which is the user-facing Flex application. If you look at the build.xml in the web project, you’ll notice that there’s also another task for compiling the administrative application, and one task called compile-flex that compiles them both:
<target name="compile-index" description="compiles index.mxml">
<exec executable="${flex.sdk.bin.dir}/mxmlc" dir="${src.dir}" >
<arg value="-context-root" />
<arg value="/bookie" />
<arg value="-load-config"/>
<arg value="${flex.config}" />
<arg value="-services"/>
<arg value="${services.config}" />
<arg value="-debug=${swf.debug}"/>
<arg value>="index.mxml" />
</exec> <move file="${src.dir}/index.swf" todir="${build.dir}" verbose="true" overwrite="true" />
</target>
To compile Flex from a system call, we just pass in a few arguments. The context root tells the application that it will probably need to make local calls with this context root appended to the beginning. It also needs to load in the LCDS configuration to learn about services we’ll configure there. After the compilation is done, we’ll copy the .swf into the build directory.
<target name="copy-changes" description="Copies changes from working dir to deploy dir">
<copy todir="${deploy.dir}" verbose="true">
<fileset dir="${war.build.dir}">
<include name="*.swf"/>
</fileset>
</copy>
<copy todir="${deploy.dir}" verbose="true">
<fileset dir="${war.src.dir}">
<include name="**/*.html"/>
<include name="**/*.jsp"/>
<include name="**/*.gif"/>
<include name="**/*.swf"/>
<include name="**/*.xml"/>
<include name="**/*.jpg"/>
<include name="**/*.png"/>
<include name="**/*.ttf"/>
<include name="**/*.js"/>
<include name="**/*.css"/>
<filename name="WEB-INF/flex/system_classes/**/*.as" negate="true" />
<filename name="WEB-INF/**/*.xml" negate="true" />
</fileset>
</copy>
</target>
The copy-changes task copies any changed .swfs to the local server, where we can see changes right away without having to restart the server. First the build directory is scanned for updated .swfs, which are moved, and then the source directory for the WAR is scanned for updates to files we can deploy without restarting the context. Ant takes care of seeing whether the versions in the working directory are newer than the ones in the server directory.
Of course, we also need to tell Ant where the local server is located, and that may be different on each developer’s machine. We’ll configure that variable location as well as the path to mxmlc in a properties file:
flex.sdk.bin.dir=/Applications/flex_sdk_2/bin
deploy.dir=/Applications/jboss/server/default/deploy/bookie.ear/bookie.war/
Here’s the properties file configured for my machine. I moved these variables to a properties file so that I can have each developer configure the properties file instead of changing the build file. Then, once I check the initial project into source control, I can have the source control system “ignore" that properties file, which means that it won’t version it. That way, no developer can accidentally override the build file with settings that are specific to his machine. All that’s left to do is provide a template for this file, or at least instructions on how to set up the project on a new developer’s machine.
Now let’s look at Maven calling Ant in the ui project:
...
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>compile</phase>
<id>swf-compilation-tasks</id>
<configuration>
<tasks>
<property name="user.home" value="${user.home}" />
<ant antfile="${basedir}/build.xml" inheritRefs="true">
<target name="compile-flex"/>
</ant>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<phase>test</phase>
<id>flexunit-tasks</id>
<configuration>
<tasks>
<property name="user.home" value="${user.home}" />
<ant antfile="${basedir}/build.xml" inheritRefs="true">
<target name="test-flex"/>
</ant>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
...
This is not much different from the data project: we pass in the user.home variable, point out the build file, and tell Maven which task to call. We call the task to compile Flex during the “compile" phase, and the task to run the FlexUnit tests during the “test" phase.
The benefit to agility by having Maven and Ant update the database schema, load data sets, compile Flex, test Flex, and so forth is that each developer has to complete only a few steps to get changes from team members integrated locally and back to developing:
1. Check out changes from source control.
1. Run a Maven package operation.
2. Run a custom Ant task to copy packaged artifacts to the local server.
This will get a clean, new version of the project on a local server with the database updated with changes for the developer to review. This works great for a QA build too. Of course, you could run any subset of these steps as needed. Also, keep in mind that anything an IDE does automatically, such as compile Java or Flex, works just as well as the Maven run build and can be augmented by the custom parts of the build.
The point is that we want any part of this build process to be automated and built with no human intervention. That way, we can feed builds to QA machines automatically, run nightly builds, and build every time someone checks something into source control. Just remember that to test Flex with FlexUnit, you need to have a web browser installed on the machine doing the builds.
Next time we'll look at the development cycle so far and dependencies in Maven. You can always find the entire series here.









Facebook Application Development
Comments
Leave a comment