12.18
This note is written based on:
- appengine-java-sdk-1.2.6
- Apache Maven 2.2.1
- Apache Ant 1.7.1
If you create an application destined to Google AppEngine using Maven, the use of the Google AppEngine SDK may not be optimal. This is because, in some instances, the generated artifact (a WAR file) is not what is expected from the SDK. In general, when generating a WAR file using Maven, an interim directory is created with all the files found inside the WAR archive. This interim directory is the expected input for the AppEngine SDK.
However, there are circumstances where an interim directory is not created. Using the Cargo Plug-in for Maven and generating an Uberwar is one example where the generated artifact does not naturally produce the needed interim directory. I find Cargo useful to build Google Wave Robots that include their own gadgets. Since Google Wave Robots must currently be hosted on Google AppEngine, I needed a script to load them automatically.
This note introduces an ANT script that unpacks the WAR file and upload the application on Google AppEngine. Two files are needed:
- build.xml This is the script that uploads the application
- build.properties This file includes user specific information
build.xml
Create a file called “build.xml” in the root directory of the Maven project. The content of the file should be as follows:
<project name="appengine-upload" default="default">
<description>
This project provides helper tasks for appengine
</description>
<!-- Allow overriding of properties -->
<property file="./build.properties"/>
<property name="appcfg.command" value="./appcfg.sh"/>
<property name="uber.target.dir" location="./target"/>
<!-- ================================= -->
<target name="default" description="Do nothing">
</target>
<!-- ================================= -->
<target name="update" depends="-update-check-variables" description="Updates appengine">
<property name="temp.dir" location="${uber.target.dir}/appengine"/>
<delete dir="${temp.dir}" failonerror="false"/>
<mkdir dir="${temp.dir}"/>
<unjar dest="${temp.dir}">
<fileset dir="${uber.target.dir}">
<include name="*.war"/>
</fileset>
</unjar>
<exec
executable="${appcfg.command}"
dir="${appcfg.dir}/bin"
inputstring="${appcfg.password}"
>
<arg line="--email=${appcfg.email} --passin update ${temp.dir}"/>
</exec>
</target>
<target name="-update-check-variables" description="Check variables">
<fail
unless="appcfg.dir"
message="Directory to appengine tools must be specified in 'appcfg.dir'"/>
<fail
unless="appcfg.email"
message="Appengine e-mail must be specified in 'appcfg.email'"/>
<fail
unless="appcfg.password"
message="Appengine password must be specified in 'appcfg.password'"/>
</target>
</project>
build.properties
Create a file called “build.properties” in the same directory as “build.xml”. The content of that file should look like:
appcfg.dir=.../appengine-java-sdk-1.2.6
# E-mail address associated with appengine account
appcfg.email=user@gmail.com
# Password associated with account
appcfg.password=password
The content of the file above should be adjusted to reflect the user’s specific SDK installation, appengine user name and password.
Running
After the files are configured correctly, uploading the application to AppEngine should be done with the following command, executed from the root directory of the project:
[...] Note in the above exmaple that AppCfg does not accept a WAR file, but a directory with the WAR content. This is produced naturally by Maven, so you can use the directory directly. More information on an automated script can be found here: Uploading a Maven generated application on Google AppEngine [...]