Requirements

Prerequisite knowledge
Intermediate to advanced Flex knowledge
 
Additional required other products 
Apache Maven 3.0.3
Flexmojos 4.0-RC2
    Plug-in info (listing of all goals and configuration settings)
 
User level
Intermediate
Required products
Flash Builder (Download trial)
Welcome back to the series on Flex, Maven, and Flexmojos. Part 1 covered Maven itself: how it works, the terminology and conventions, and the Flexmojos plug-in. If you haven't read Part 1 and are new to Maven, I thoroughly encourage you to peruse it prior to reading this article, as there are many Maven conventions in place here that will be assumed knowledge.
 
In this article, I'm going to take you deeper into the world of Maven and Flexmojos and look at project setup, finding dependencies, configuration, unit testing, and adding projects to the build.
 
Note: In the previous article I mentioned that this article would also cover Flash Builder integration. I've decided to cover the topic in full, including the m2eclipse plug-in, in a separate article on Maven and Flash Builder.
 

 
Project setup

 
Folder structure
As you saw in Part 1, when you build Maven projects, you simply tell it—and hence the Flexmojos plug-in—where to find the root source folder via the following parameter in the POM:
 
<sourceDirectory> . . . </sourceDirectory>
This directory location itself is arbitrary; however, you will regularly see this convention in Flex projects:
 
<sourceDirectory>src/main/flex</sourceDirectory> <testSourceDirectory>src/test/flex</testSourceDirectory>
The typical folder structure, with some added files, looks like Figure 1.
 
Figure 1. Typical project layout
Figure 1. Typical project layout

Following this convention enables you to segregate your source properly from your unit tests (preventing their inclusion in your actual build). It also gives you somewhere (/src/main/resources) to keep non-source assets, such as resource bundles for different locales, CSS files, fonts, images, and other miscellaneous resources.
 
 
Using an archetype
Maven supports project templates, called archetypes. An archetype provides a basic project skeleton to help developers get started. Flexmojos provides these as well, helping you begin a new project.
 
Try generating a project from this simple archetype yourself:
 
mvn archetype:generate -DarchetypeRepository=http://repository.sonatype.com/content/groups/flexgroup -DarchetypeGroupId=org.sonatype.flexmojos -DarchetypeArtifactId=flexmojos-archetypes-application -DarchetypeVersion=4.0-RC2
After you run the command, Maven will download the necessary artifacts for the archetype and then ask you for the groupId , artifact , version and package (typically, the same as your groupId ). Once the download is completed, Maven (via Flexmojos) creates the basic structure for you.
 
Tip: An archetype is just another build artifact in Maven. The one above uses this POM to build.
 
 
What to check in to source control
One of the advantages of having a project management script—a POM—is that you have a single point of responsibility for managing how a project should be built. Developers are sometimes tempted to add .project files and the /libs folder to source control (hereafter referred to as SCM—Source Control Management). They argue that it is a nice convenience to help developers get up to speed quickly. This practice is to be avoided for two reasons:
 
  1. The POM should be the central point of contact for how to build and manage your project. IDE project configurations—such as .project, .idea, and so on—have their own mechanisms for building and dependency management. If you add these files to SCM, you are effectively duplicating the build/dependency functionality of Maven and will have to consolidate them manually with your POM at regular intervals.
  2. By checking in .project files, you restrict current and future developers to the same IDE and version as yourself.
As a rule, do check in the following:
 
  • pom.xml
  • src/*.*
  • settings.xml (if any)
Do NOT check in:
 
  • .project, .settings, .actionScriptProperties, .flexProperties, .idea
  • /libs
ABSOLUTELY NEVER check in:
 
  • /bin-debug, /bin-release
  • /target
Tip: if you want to share your builds (both releases and snapshots) with other developers, use Nexus, that is what it is for. I'll cover Nexus in depth in the final article.
 
Note: There are occasions when checking in the libs folder can be appropriate. Typically all your dependencies should be hosted or proxied via an internal Nexus install (covered in detail in the next article). There are occasions, however, when hosting a repository is out of scope. For example, when I put example projects up on Github, I check in third-party SWC dependencies and a brief note on using install:install-file to help developers new to Maven get started running the build.
 

 
Finding dependencies

One thing I touched on briefly in Part 1 was how to find dependencies for your POMs. Almost everything you can and will build depends on third-party libraries. The Flex compiler and framework are both simply dependencies. Luckily, many of the most common dependencies are hosted on remote repositories.
 
To demonstrate the process of finding a dependency, I will use an example that will be useful later on - finding a specific unit testing framework.
 
What I want is flexunit 4.1.0-8—the same that is bundled with Flash Builder 4.5.1.
 
 
Step 1: Maven Central
First off, I check Maven Central via search.maven.org. Recall that Maven Central is defined in the super POM and, if I find it in here, I won't need to add any extra repository information to my POM or settings file. I enter flexunit into the search box and it yields the three items shown in Figure 2:
 
Figure 2. Searching Maven Central
Figure 2. Searching Maven Central

I can see from this that I've found asmock-flexunit1 and the two Flexmojos unit testing projects—one for FlexUnit and the other for FlexUnit4 . These are projects that Flexmojos requires to run these unit testing frameworks, not the dependency itself. Clearly, none of these satisfies my need, so I'll need to look elsewhere.
 
 
Step 2: Sonatype
If the dependency can't be found in Maven Central, the next step is to check the Sonatype repository: repository.sonatype.org. Recall from Part 1 that within this repository are all of the Flex SDK and compiler artifacts—it's the repository that I'm referencing for my Flex builds, so looking in here is the next best bet (see Figure 3).
 
Note: The Flex SDK and compiler artifacts have been added to the Sonatype "flexgroup" section by the community. Currently, Adobe does not deploy its artifacts to a publicly accessible repository. This is why new versions of the Flex SDK may not appear instantly in the Sonatype repository. The hope is that one day Adobe will deploy its releases to Maven Central as soon as they are published.
 
Figure 3. Searching Sonatype
Figure 3. Searching Sonatype

I can see from Figure 3 that yes, there is a FlexUnit4 dependency; however, it is not the version I require.
 
 
Step 3: The Internet
Well, now I've got to try my luck on the web. It's not in Maven Central or Sonatype, so I could try to see if there is another repository elsewhere hosting my dependency. There are repositories available for Java and Google, but they are unlikely to help me.
 
 
Last alternative: Install it internally
At this point, my best solution is to install the dependency into my local repository (or better yet, install it into my internal Nexus instance—but I'll cover that in the next article). This means I need to find the SWC I require and run the install-file goal. In this instance, FlexUnit 4.1.0.8 is available within my Flash Builder install via:
 
Adobe Flash Builder 4.5/eclipse/plugins/com.adobe.flexbuilder.flexunit_4.5.1.313231/flexunitframework/libs/version4libs/FlexProject/flexunit-4.1.0-8-flex_4.1.0.16076.swc
Note: This build of FlexUnit is built against Flex 4.1, but is satisfactory for my purposes.
 
So, as in the previous article, I install the file to my local repository. I know from checking Sonatype in the previous step that I should follow the following convention:
 
groupId: com.adobe.flexunit artifactId: flexunit
Tip: If I wasn't able to find the groupId and artifactId, then, in the worst case, I could have simply made them up. It is an internal dependency, after all; just remember that consistency is the key.
 
So, from the location of the SWC I want to install, I run:
 
mvn install:install-file -Dfile=flexunit-4.1.0-8-flex_4.1.0.16076.swc -DgroupId=com.adobe.flexunit -DartifactId=flexunit -Dversion=4.1.0-8 -Dpackaging=swc
Then I can safely add the following dependency to my POM:
 
<dependency> <groupId>com.adobe.flexunit</groupId> <artifactId>flexunit</artifactId> <version>4.1.0-8</version> <type>swc</type> <scope>test</scope> </dependency>
Truth be told, your organization or institution should have its own install of Nexus, and the dependencies can be added to the third-party repository within it. That way you share these dependencies to all developers on the project. I'll cover this in the next article of this series.
 

 
Customizing Flexmojos

Every release of Flexmojos produces a site report that lists usage of the plug-in and the list of goals and configuration settings.
 
To see the latest plug-in info, check the docs for 4.0-RC2.
 
Within your POM, the <configuration> section actually aggregates all of the parameters for the plug-in. An example might be:
 
<project> ... <build> <plugins> <plugin> <groupId>org.sonatype.flexmojos</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <version>4.0-RC2</version> <extensions>true</extensions> <configuration> <compilerWarnings> <warn-no-constructor>false</warn-no-constructor> </compilerWarnings> <debug>false<debug> <coverage>true</coverage> <aggregate>true<aggregate> </configuration> </plugin> </plugins> </build> ... </project>
These correspond to:
 
  1. From goals compile-swf , compile-swc and asdoc :
  1. From goal test-run :
  1. From goal asdoc (to generate ASDoc files):
Tip: As you might have guessed, the order of the parameters is irrelevant.
 
In the previous article, I covered the phases within the SWF and SWC lifecycles (repeated below in Figure 4). As such, if I were to run mvn clean install on, say, a SWF packaged project, I know that the plug-in goals compile-swf, test-compile and test-run will execute. Thus the configuration settings debug , coverage , and compilerWarnings will be read; aggregate is irrelevant for the default lifecycle and will be ignored. If however we were to run mvn flexmojos:asdoc then the parameters debug and compilerWarnings would still apply (as they also exist as parameters within the asdoc goal), as well as aggregate; coverage, on the other hand, would be ignored.
 
Note: Instead of aggregating all configuration together, and for greater control, you can customize the plug-in itself. The <executions> setting allows configuration of the phases themselves—the goals within them and the configuration for each. This is out of scope for this article series, but for an introduction into the usage of custom executions, check out Introduction to the Build Lifecycle from the Maven docs.
 

 
Unit testing

Out of the box, Flexmojos supports automated unit tests as part of the build process. Flexmojos produces Surefire reports that are placed within the /target/surefire-reports folder. By convention, if any unit tests fail or have runtime errors, the build itself will fail.
 
Recall from Part 1 that the Maven build lifecycle conducts tests after a standard compilation. SWF, SWC, and AIR builds all perform standard unit tests (see Figure 4).
 
Figure 4. Default SWF lifecycle
Figure 4. Default SWF lifecycle

In order to kick the process off, you must:
 
  1. Supply a <testSourceDirectory> to your POM. This should point to a folder that hosts your unit tests; typically, it is src/test/flex.
  2. Add your unit testing dependencies (for example, FlexUnit , FlexUnit4, or asunit ).
  3. Make sure Flexmojos can find a standalone Flash Player on your PATH.
I'm going to outline these three in detail. To follow along, check the example project on Github.
 
 
Step 1: Setup
Every time you build, Flexmojos will attempt to compile and run any unit tests (matching Test*.as and *Test.as by default) it finds and execute them. You can customize this matching pattern using the configuration setting includeTestFiles (see the "Test configuration settings" section).
 
You need to ensure you have a folder for your tests. The general rule is src/test/flex, but as mentioned before, it is up to you.
 
Inside that folder or any subfolder, you need at least one class beginning or ending in "Test" that has unit tests. As I'm using the example from Github, I'll use a FlexUnit4 test:
 
public class TestRandomCity { protected var cities:RandomCity; [Before] public function setUp():void { cities = new RandomCity(); } [Test] public function testGetNext():void { for (var i:int = 1; i < 100; i++) assertThat(cities.next); } [After] public function tearDown():void { cities = null; } }
 
Step 2: Test Dependencies
From the earlier section, recall that the FlexUnit 4.0-rc-1 dependency is hosted on Sonatype. As such, I could simply use that version, but as I installed the 4.1.0-8 version into my repository earlier, I'd rather use:
 
<dependency> <groupId>com.adobe.flexunit</groupId> <artifactId>flexunit</artifactId> <version>4.1.0-8</version> <type>swc</type> <scope>test</scope> </dependency>
Notice anything different? I've added the parameter <scope> of test . This ensures that the dependency will only be used when compiling unit tests, not when compiling the artifact itself. The next and final article in the series will cover scope in more depth.
 
If FlexUnit4 isn't your cup of tea, never fear: Flexmojos supports a plethora of unit testing frameworks. Checkout the Flexmojos project on Github for some unit testing examples using various frameworks.
 
You may also find yourself requiring toolsets like fluint, hamcrest-as3 or mockolate. Follow the process for finding dependencies from the "Finding dependencies" section. More often than not, you'll find yourself having to install the SWCs locally.
 
 
Step 3: Finding Flash Player
To run the unit tests from Maven, Flexmojos needs to find the Flash Player executable. You must make sure Flash Player (Flash Player on OS X, flashplayer on Linux, and Flashplayer.exe on Windows) is available on your PATH. You can download the stand-alone Flash Player Projector from Adobe.
 
In Windows, unpack the download and add that location to your PATH via the My Computer > Advanced > Environment Variables command. On OS X, I moved the downloaded Flash Player.app to usr/local/bin and added the following to my ~/.bash_profile:
 
export FLASH_PLAYER='/usr/local/bin/Flash Player.app/Contents/MacOS' export PATH=${M2_HOME}/bin:$FLASH_PLAYER:${PATH}
If you're still stuck, here are some additional instructions from Flexmojos.
 
 
Configuring the tests
As mentioned earlier, the configuration of your POM combines settings from various goals. Regarding unit tests, you have two goals to work with:
 
In those links, you'll find collections of parameters that you can use to customize how your project should compile the unit tests and how they should run.
 
For example, if you want to modify the pattern matching of unit tests, you could apply the following to your POM (inside the Flexmojos plug-in section):
 
<configuration> <includeTestFiles> <includeTestFile>*Tests.as</includeTestFile> </includeTestFiles> </configuration>
Tip: If you want to skip tests in your build at any time, simply use -DskipTests as in mvn clean install -DskipTests .
 
 
Running tests on a build server
Automating unit tests on a Linux build server, which typically has no GUI (and as such is headless), requires a bit more effort. Currently, Flexmojos uses Xvfb, a framebuffer tool, to emulate the GUI for Flash Player. For more information, check out this post from Flexmojos:
 
 
Code coverage
Want to see how much of your code is covered by your unit tests? Flexmojos 4 includes the generation of code coverage reports in Cobertura. It uses Apparat (written in Scala) to produce coverage reports (and incidentally, also for optimization).
 
<configuration> ... <coverage>true</coverage> <coverageProvider>cobertura</coverageProvider> <coverageReportFormat>html</coverageReportFormat> ... </configuration>
This outputs a collection of HTML files with line-by-line code coverage under /target/coverage. If you'd rather integrate it into your build server, switch the <coverageReportFormat> parameter to xml .
 
Tip: If you're using Hudson or Jenkins, add the Cobertura plug-in and use the following XML report pattern to aggregate all of your Maven modules' coverage data: **/target/coverage/coverage.xml .
 

 
Adding projects

Soon after finding your feet in Maven, it's time to build a real-world project. As such, a simple application with a few dependencies is hardly going to cut the mustard.
 
You can find the code to this example on Github.
 
As you add projects to your application—such as libraries and runtime modules—you will need to create POMs for each of them. The typical process is to:
 
  1. Create a parent POM that contains all settings and configuration to share across the application.
  2. Create directories for each project within your application.
  3. Within each project, create POM and add source files.
An example might look like:
 
Figure 5. Project with multiple POMs
Figure 5. Project with multiple POMs

Two mechanisms in Maven let you reference one POM in another: inheritance and aggregation.
 
 
Inheritance
As mentioned earlier, all POMs inherit from the Maven super POM. This provides a collection of settings for each execution, including the repository location of Maven Central.
 
If you want to create a child POM that inherits from a parent, do the following:
 
  1. Create a parent POM with a <packaging> parameter of pom , enabling it to be used as a superclass for inheritance. Any configuration in this POM will be shared among all children:
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.justinjmoses.flexmojos-introduction.libraries-example</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> </project>
  1. Create a child POM that inherits from the parent:
<project> <parent> <groupId>org.justinjmoses.flexmojos-introduction.libraries-example</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>library</artifactId> <packaging>swc</packaging> </project>
Note: the child POM still needs to refer to the parent's version number. It can inherit this version for itself, however (and the groupId , for that matter).
 
Tip: Another Maven convention is at work here. The relative URL of the parent POM is assumed to be ../pom.xml. You can override this with the <relativeUrl> parameter within the <parent> element.
 
Now you can individually build any of the child POMs and be assured that they will inherit their settings from the one parent. So, what if you want to build all at once? That's where aggregation comes in.
 
 
Aggregation
To process other POMs from within a POM, you need to create definitions of the location of these other POMs. These projects are referred to as modules in Maven.
 
As such, you can add the following modules to your project, and it becomes an aggregator project.
 
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.justinjmoses.flexmojos-introduction.libraries-example</groupId> <artifactId>parent</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>application</module> <module>library</module> </modules> </project>
Note: As with inheritance, the <packaging> parameter must be set to pom to perform aggregation.
 
Tip: The actual module name corresponds to the relative folder of the module, not the artifact inside the module. Typically, modules live directly off the aggregator project. Alternate locations are valid, however: for example, <module>../../my-project</module>
 
As part of the aggregation process, Maven ensures that it determines what interdependencies—if any—there are between the modules and constructs a build order to match.
 
For example, when you add the following dependency to the application (SWF) module:
 
<dependency> <groupId>org.justinjmoses.flexmojos-introduction.libraries-example</groupId> <artifactId>library</artifactId> <version>1.0.0-SNAPSHOT<version> <type>swc</type> </dependency>
Maven will determine that the library (SWC) module must be built first in order for the application (SWF) to start.
 
Note: Don't confuse Maven modules with Flex runtime modules—they are completely different.
 
 
Combining inheritance with aggregation
With each child POM inheriting from the parent POM and the parent POM aggregating the child modules, the project is now integrated, and you can kick off the build from the parent and put any common configuration into the parent POM.
 
Most of the time, your projects will combine inheritance and aggregation. Nevertheless, there may be instances where you do not want to use both. Aggregating simply allows you to start processing multiple POMs, regardless of their relationship to the currently executing POM. Inheritance, on the other hand, lets you share and override settings from a parent to a child.
 
With both tools employed, you can update your interdependency in the application (SWF) module to:
 
<dependency> <groupId>${project.groupId}</groupId> <artifactId>library</artifactId> <version>${project.version}<version> <type>swc</type> </dependency>
The ${project.groupId} and ${project.version} settings are shared across all of the child POMs via inheritance, so it's a convenience to not have to explicitly state the interdependencies within the child POMs.
 

 
Where to go from here

This article has covered project structure, setup, and archetypes; a workflow for finding dependencies; customizing the various goals within Flexmojos; automated unit tests and code coverage, and finally, adding additional projects to your build with inheritance and aggregation.
 
The final article in this series talks about dependency scope and discuss the usage of RSLs, runtime Flex modules, WAR packaging, build profiling and ASDoc support.
 
Here are some useful resources: