2011-06-22

Using maven to build a qooxdoo application

Qooxdoo is a framework to build rich Internet applications. It is very promising. The qooxdoo language use a syntax similar to javascript, but it is fully object oriented. It generates optimized javascript that runs on most populars browsers.

Qooxdoo code is compiled using python script provided with the SDK.

There are few receipe to build qooxdoo apps using maven, but I rolled up my own, and I share it with you, because I think it is hasslefree. You even don't need to install python if you want!

This is possible thanks to jspresso maven repository that hosts the latest qooxdoo-sdk releases

I'm a maven newbee, so please help me make theses pom.xml snipets simplier or standard.

Let's begin.

Repository

First you need to specify the jspresso repository.

    <repositories>
        <repository>
            <id>jspresso.org</id>
            <url>http://repository.jspresso.org/maven2/</url>
        </repository>
    </repositories>

Plugin

During the compile phase, It fetches jython (Python on the JVM)
Then extracts jython.jar and the Lib directory from the jython-installer.jar
After that, it updates jython.jar (it adds the Lib directory to the jython.jar so it contains all the necessary stuff to compile qooxdoo).

On next compile, it won't do this long process again, since it checks for the existence of the file before fetching it from the Internet.


During the clean phase, it removes all the created files and directories.
As you can see, I've used maven-antrun-plugin since I'm more familiar with ant.
  
<plugin>
    <!-- we download the jython.jar from internet using ant, since it doesn't
        exists in maven repositories -->
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>getJython</id>
            <phase>compile</phase>
            <configuration>
                        <target name="getJython">
                        <taskdef resource="net/sf/antcontrib/antcontrib.properties"
                            classpathref="maven.plugin.classpath" />
                        <if>
                            <not>
                                <available file="${project.basedir}/tools/jython.jar" />
                            </not>
                            <then>
                                <get
                                    src="http://sourceforge.net/projects/jython/files/jython/2.5.2/jython_installer-2.5.2.jar/download"
                                    dest="${project.basedir}/tools/jython_installer-2.5.2.jar"
                                    usetimestamp="true" />
                                <unzip src="${project.basedir}/tools/jython_installer-2.5.2.jar"
                                    dest="${project.basedir}/tools" overwrite="false">
                                    <patternset>
                                        <include name="jython.jar" />
                                        <include name="Lib/**" />
                                    </patternset>
                                </unzip>
                                <zip zipfile="${project.basedir}/tools/jython.jar" update="true">
                                    <fileset dir="${project.basedir}/tools/">
                                        <include name="Lib/**" />
                                    </fileset>
                                </zip>
                            </then>
                        </if>                   
                        </target>               
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
        <execution>
            <id>deleteJython</id>
            <phase>clean</phase>
            <configuration>
                <target>
                    <delete dir="${project.basedir}/tools/qooxdoo-sdk"/>
                    <delete file="${project.basedir}/tools/jython_installer-2.5.2.jar" />
                    <delete file="${project.basedir}/tools/jython.jar" />
                    <delete dir="${project.basedir}/tools/Lib" />
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
   <dependencies>
      <dependency>
        <groupId>ant-contrib</groupId>
        <artifactId>ant-contrib</artifactId>
        <version>20020829</version>
      </dependency>
    </dependencies>
</plugin>

Dependencies

In the dependency part, the only needed thing is qooxdoo-sdk :

<dependencies>
        <dependency>
            <groupId>org.qooxdoo</groupId>
            <artifactId>qooxdoo-sdk</artifactId>
            <version>1.4.1</version>
            <type>zip</type>
        </dependency>
<!-- ... -->
</dependencies>


Profiles

The most interesting part is happening in the profiles.
This is where we unpack the qooxdoo-sdk, and we compile the qooxdoo code.

Qooxdoo code is compiled from src/main/qooxdoo and the compiled code will end up in
target/qooxdoo.

The pom.xml file allow two different way of invoking the qooxdoo compiler, one with "native" python. The other one using the jython we downloaded, using jython to compile is a lot slower, but it is convenient since  there is nothing more to install.

If you wish to build the qooxdoo code using native python, you need to download and install it. You will notice that it is a lot faster to compile the qooxdoo source code this way. BEWARE Python 3 is not supported, 2.5+ required.

Here is the profile to build using native python. It activates when you pass -DbuildQooxdoo=true.
You can specify where to look for the python executable if it is not in the PATH.

<profile>
    <id>qooxdoo-building</id>
    <properties>
        <pythonExecutable>python</pythonExecutable>           
    </properties>
    <activation>
        <property>
            <name>buildQooxdoo</name>
            <value>true</value>
        </property>
    </activation>
   
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                        <id>compile-js</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                </executions>
        <configuration>
                  <executable>${pythonExecutable}</executable>
                  <workingDirectory>${project.basedir}</workingDirectory>
                  <arguments>
                     <argument>${project.basedir}/tools/qooxdoo-sdk/tool/bin/generator.py</argument>
                     <argument>build</argument>
                     <argument>--macro=QOOXDOO_PATH:${project.basedir}/tools/qooxdoo-sdk</argument>
                <argument>--macro=BUILD_PATH:${project.build.directory}/qooxdoo</argument>
                     <argument>--config=${project.basedir}/src/main/qooxdoo/config.json</argument>
                  </arguments>
              </configuration>
            </plugin>
        </plugins>
    </build>
</profile>



Here is the profile to build using jython. It activates when you pass -DbuildQooxdooJython=true.

<profile>
    <id>qooxdoo-building-jython</id>
    <activation>
        <property>
            <name>buildQooxdooJython</name>
            <value>true</value>
        </property>
    </activation>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                        <id>compile-js</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                </executions>
                <configuration>
                    <executable>${java.home}/bin/java</executable>
                    <workingDirectory>${project.basedir}</workingDirectory>
                    <arguments>
                        <argument>-Dpython.home=${project.build.directory}</argument>
                        <argument>-classpath</argument>
                        <argument>${project.basedir}/tools/jython.jar</argument>
                        <argument>org.python.util.jython</argument>
                        <argument>${project.basedir}/tools/qooxdoo-sdk/tool/bin/generator.py</argument>
                        <argument>-v</argument>
                        <argument>build</argument>
                        <argument>--macro=QOOXDOO_PATH:${project.basedir}/tools/qooxdoo-sdk</argument>
                        <argument>--macro=BUILD_PATH:${project.build.directory}/qooxdoo</argument>
                        <argument>--config=${project.basedir}/src/main/qooxdoo/config.json</argument>
                    </arguments>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>

Here is the profile to unpack qooxdoo-sdk, it activates when tools/qooxdoo-sdk is missing.

        <profile>
            <id>qooxdoo-unpacking</id>
            <activation>
                <file>
                    <missing>tools/qooxdoo-sdk</missing>
                </file>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-dependency-plugin</artifactId>
                        <version>2.2</version>
                        <executions>
                            <!--Import qooxdoo sdk and add it to target directory -->
                            <execution>
                                <id>extract-qooxdoo-sdk</id>
                                <phase>process-resources</phase>
                                <goals>
                                    <goal>unpack-dependencies</goal>
                                </goals>
                                <configuration>
                                    <includeArtifactIds>qooxdoo-sdk</includeArtifactIds>
                                    <outputDirectory>tools/qooxdoo-sdk</outputDirectory>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>


Using this pom.xml snipets you should be up and running in a minute!

As I write this post, I notice that I could do better by invoking getJython in the qooxdoo-building-jython profile only. This is one improvement I  see, but you will probably spot more than one!

Happy Qooxdooing!