Setting up your first modules

A good starting point to setup your firs modules is to use the archetypes flexmojos provides. There are generally 3 archetypes:

  1. application archetype for building SWFs
  2. library archetype for building SWCs
  3. webapp archetype to create 3 Modules (1 application, 1 library and one war module to host a flex based web-application)

The code generated is propably a minimal as you can get with flexmojos, but it works.
Let's have a look at the different modules:

Application module

by using the folowing command you generate a clean application module:

mvn archetype:generate -DarchetypeRepository=http://repository.sonatype.com/content/groups/flexgroup -DarchetypeGroupId=org.sonatype.flexmojos -DarchetypeArtifactId=flexmojos-archetypes-application -DarchetypeVersion=4.0-SNAPSHOT

The generated module contains the following directory structure:

src
 - main
    - flex
       - Main.mxml
    - resources
 - test
    - flex
pom.xml

/src/main/flex will hereby contain the flex code. Currently it will contain one file: Main.mxml

/src/main/resources will contain any static rsoucres such as images, fonts, media-files

/src/test/flex can contain flex unit-testing code. The generated module contains one sample Testcase inside the package you provided when generating the module.

Currently the file we are going to have a deeper look at is the pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
  <!--

    Copyright 2008 Marvin Herman Froeder
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>de.cware</groupId>
  <artifactId>testapp</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>swf</packaging>

  <name>testapp Flex</name>

  <build>
    <sourceDirectory>src/main/flex</sourceDirectory>
    <testSourceDirectory>src/test/flex</testSourceDirectory>
    <plugins>
      <plugin>
        <groupId>org.sonatype.flexmojos</groupId>
        <artifactId>flexmojos-maven-plugin</artifactId>
        <version>4.0-SNAPSHOT</version>
        <extensions>true</extensions>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>com.adobe.flex.framework</groupId>
      <artifactId>flex-framework</artifactId>
      <version>4.5.0.18623</version>
      <type>pom</type>
    </dependency>

    <dependency>
      <groupId>com.adobe.flexunit</groupId>
      <artifactId>flexunit</artifactId>
      <version>0.85</version>
      <type>swc</type>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>

Details

The packaging of a flex project building a SWF is "swf" without this Flexmojos won't do anything at all.

Maven assumes sources and tests to be located in the directories "src/main/java" and "src/test/java". As we are not building a java module, we want our directories to be "src/main/flex" and "src/test/flex". As Flexmojos uses the Maven resolvers, we have to tell Maven where to look. This is done by re-configuring the directries using the "sourceDirectory" and "testSourceDirectory" properties.

Since we are building a Flex application, we need access to the Flex libraries. There are quite a lot of different modules we would have to manually import. As a conveniance module "flex-framework" pom-module handles all of these imports.

Finally the reference to flexunit imports the flexunit unit-testing framework. Flexmojos won't work without at least one unittesting framework.

Things I reccomend to change

In the current setting flexmojo guesses the main class. I don't know how this is exactly done, but I would assume that at first it looks for Application and Module classes and simply picks one. This is ok if you only have one of these classes, but I often have multiple Application mains for debugging purposes, so I don't like the idea of flexmojos guessing which one. You can explicitly tell flexmojos which one to use by using the sourceFile parameter.

In the current configuration Flexmojos will use the Flex-SDK that is configured in it's master pom. I like to have direct control over the version I am using. Changing the version of the "flex-framework" dependency will cause build problems as the flex compiler no longer matches the version of the sdk we are using to develop. This problem is easily avoidable by explicitly adding a dependency to the compiler in the same version.

There semes to be a Maven-Bug that breaks the handing of resources. If you want to keep your resources in a directory "src/main/resources" and be able to reference them normally, you need to add a reference to the flexmojos-threadlocaltoolkit-wrapper before the flex compiler.

If you don't explicitly reference a theme, flexmojos will guess one depending on the import of halo or spark dependencies. Unfortunatley it seems it tries to download them from the wrong path and therefore tries to fetch the theme css every time a flex module is built and this slows down your build dramatically Thats why I add a theme section referencing my own local repository in order to avoid this.

<?xml version="1.0" encoding="UTF-8"?>
  <!--

    Copyright 2008 Marvin Herman Froeder
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>de.cware</groupId>
  <artifactId>testapp</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>swf</packaging>

  <name>testapp Flex</name>

  <properties>
    <flex.version>4.1.0.16248</flex.version>
    <flexmojos.version>4.0-SNAPSHOT</flexmojos.version>
  </properites>

  <build>
    <sourceDirectory>src/main/flex</sourceDirectory>
    <testSourceDirectory>src/test/flex</testSourceDirectory>
    <plugins>
      <plugin>
        <groupId>org.sonatype.flexmojos</groupId>
        <artifactId>flexmojos-maven-plugin</artifactId>
        <version>${flexmojos.version}</version>
        <extensions>true</extensions>
        <configuration>
          <sourceFile>MyMain.mxml</sourceFile>
          <themes>
            <theme>${settings.localRepository}/com/adobe/flex/framework/framework/${flex.version}/configs_zip/themes/Spark/spark.css</theme>
          </themes>
        <dependencies>
          <dependency>
            <groupId>org.sonatype.flexmojos</groupId>
            <artifactId>flexmojos-threadlocaltoolkit-wrapper</artifactId>
            <version>${flexmojos.version}</version>
          </dependency>
          <dependency>
            <groupId>com.adobe.flex</groupId>
            <artifactId>compiler</artifactId>
            <version>${flex.version}</version>
            <type>pom</type>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>com.adobe.flex.framework</groupId>
      <artifactId>flex-framework</artifactId>
      <version>${flex.version}</version>
      <type>pom</type>
    </dependency>

    <dependency>
      <groupId>com.adobe.flexunit</groupId>
      <artifactId>flexunit</artifactId>
      <version>0.85</version>
      <type>swc</type>
      <scope>test</scope>
    </dependency>
  </dependencies>

</project>

Library Module

The difference between an application module and a library module is very small. By setting the packaging of the module to "swc" Flexmojos will generate a swc-file that can then be used in other flex modules. Due to the nature of swc-files there is no need to configure a sourceFile.

Webapp Module

The third type of modules is a Webapp module. Flexmojos does not really have any compilations stuff to do in a Webapp, but in order to assemble an application a lot of different Flash resources have to be copied to the webapp output directory so they can be packaged in the war-file.

Here comes one of my webapp poms:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>de.cware.cweb.ee</groupId>
        <artifactId>electronic-emotions</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <groupId>de.cware.cweb.ee</groupId>
    <artifactId>electronic-emotions.webapp</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>Electronic-Emotions: Webapp</name>

    <build>
        <finalName>Electronic-Emotions</finalName>
        <plugins>
            <plugin>
                <groupId>org.sonatype.flexmojos</groupId>
                <artifactId>flexmojos-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>copy-flex-resources</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>de.cware.cweb</groupId>
            <artifactId>cweb-core-utils-webapp</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <!--
            Add the flex client (causes the SWFs to be copied)
        -->
        <dependency>
            <groupId>de.cware.cweb</groupId>
            <artifactId>cweb-core.client.application</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>swf</type>
        </dependency>
        <!--
            Add the skin-module for the entire application
        -->
        <dependency>
            <groupId>de.cware.cweb.ee</groupId>
            <artifactId>electronic-emotions.skins.thesurface</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>swf</type>
        </dependency>

        <!--
            Add the modules ...
        -->
        <dependency>
            <groupId>de.cware.cweb</groupId>
            <artifactId>cweb-mod.communicator.module</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <type>pom</type>
        </dependency>


... And a lot more flex modules ...

    </dependencies>
</project>

Ok ... now what would happen with a normal Maven build of a war module without any flexmojos-voodoo?

Unfortunately no SWF resources would have been copied. This is where the copy-flex-resources goal of flexmojos comes in. It processes the direct dependencies and all transifive dependencies and copies all of these to the webapp output directory. The really cool thing about it is that it doesn't just stupidly copy all swfs to the output, but it also is able to detect rsl-references (Flex Runtime Shared Libraries) and copies these to a special "rsls" directory in the output. 

If you are getting NullPointerExceptions from the CopyMojo, you need to define an additional config parameter to the flexmojos configuration of your war-pom:
"<useFinalName>false</useFinalName>"