Google Appengine ships with an Eclipse plugin which appears to assume a particular project structure. Since some of us don’t use Eclipse, and all of us use maven, we prefer to use the standard maven structure for the project, which works equally well standalone, and with all major IDEs.
Because the jars distributed Google App Engine appear to different from the same version jars available in the maven repositories, this procedure will require you to add pretty much all Google distributed jars to your local repository which is obviously far from ideal.
Download the SDK
Start by downloading the Google Appengine SDK for Java here: http://code.google.com/appengine/downloads.html, and unzip the distribution package, in our case appengine-java-sdk-1.2.0.zip
Publish the library jars to Maven repository
Next publish the appengine libraries to your maven repository so that we can list them as dependencies in your pom.xml file.
mvn install:install-file -Dfile=lib/appengine-tools-api.jar -DgroupId=com.google -DartifactId=appengine-tools -Dversion=1.2.0 -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -Dfile=lib/user/appengine-api-1.0-sdk-1.2.0.jar -DgroupId=com.google -DartifactId=appengine-sdk-1.2.0-api -Dversion=1.2.0 -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -Dfile=lib/shared/appengine-local-runtime-shared.jar -DgroupId=com.google -DartifactId=appengine-local-runtime-shared -Dversion=1.2.0 -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -Dfile=lib/user/orm/datanucleus-appengine-1.0.0.final.jar -DgroupId=org.datanucleus -DartifactId=datanucleus-appengine -Dversion=1.0.0.final -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -Dfile=lib/user/orm/datanucleus-appengine-1.0.0.final.jar -DgroupId=org.datanucleus -DartifactId=datanucleus-appengine -Dversion=1.0.0.final -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -Dfile=lib/user/orm/datanucleus-core-1.1.0.jar -DgroupId=org.datanucleus -DartifactId=datanucleus-core -Dversion=1.1.0 -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -Dfile=lib/user/orm/datanucleus-jpa-1.1.0.jar -DgroupId=org.datanucleus -DartifactId=datanucleus-jpa -Dversion=1.1.0 -DgeneratePom=true -Dpackaging=jar
We are also going to need the jdo-api-2.3-SNAPSHOT artifacts and the transactiona-api-1.1.jar (which can be downloaded from http://download.java.net/maven/1/javax.transaction/jars/ ) as they do not appear to be available in the central maven repository.
mvn install:install-file -Dfile=lib/user/orm/jdo2-api-2.3-SNAPSHOT.jar -DgroupId=javax.jdo -DartifactId=jdo2-api -Dversion=2.3-SNAPSHOT -DgeneratePom=true -Dpackaging=jar
mvn install:install-file -DgroupId=javax.transaction -DartifactId=transaction-api -Dversion=1.1 -Dpackaging=jar -Dfile=/Users/torstenek/Desktop/transaction-api-1.1.jar
The enhancer tools from central has a dependency to a different version of datanucleus-core, so we need to create a local artifact for this one as well.
mvn install:install-file -Dfile=lib/tools/orm/datanucleus-enhancer-1.1.0.jar -DgroupId=org.datanucleus -DartifactId=datanucleus-enhancer -Dversion=1.1.0 -DgeneratePom=true -Dpackaging=jar
This project also uses the maven-datanucleus-plugin (see the POM). We had to hack the pom file to ensure that the datanucleus dependencies match point to the versions we just added manually to the repository.
repository/org/datanucleus/maven-datanucleus-plugin/1.1.0/
Create the Maven project structure and pom.xml
The simplest way to create a maven webapp project is to use the maven archetype plugin. Let’s create a maven version of the guestbook demo included in the SDK.
mvn archetype:create -DgroupId=com.google -DartifactId=guestbook -DarchetypeArtifactId=maven-archetype-webapp
Configure your POM
The finished POM for the guestbook project should look something like this
<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>com.google</groupId>
<artifactId>guestbook</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>guestbook Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google</groupId>
<artifactId>appengine-tools</artifactId>
<version>1.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google</groupId>
<artifactId>appengine-local-runtime-shared</artifactId>
<version>1.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google</groupId>
<artifactId>appengine-sdk-1.2.0-api</artifactId>
<version>1.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<artifactId>standard</artifactId>
<groupId>taglibs</groupId>
<version>1.1.2</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<artifactId>jstl</artifactId>
<groupId>javax.servlet</groupId>
<version>1.1.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-el_1.0_spec</artifactId>
<version>1.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jsp_2.1_spec</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-servlet_2.5_spec</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jpa_3.0_spec</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jta_1.1_spec</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-appengine</artifactId>
<version>1.0.0.final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.jdo</groupId>
<artifactId>jdo2-api</artifactId>
<version>2.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.datanucleus</groupId>
<artifactId>datanucleus-jpa</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>DataNucleus_Repos2</id>
<name>DataNucleus Repository</name>
<url>http://www.datanucleus.org/downloads/maven2</url>
</repository>
</repositories>
<build>
<finalName>guestbook</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.datanucleus</groupId>
<artifactId>maven-datanucleus-plugin</artifactId>
<version>1.1.0</version>
<configuration>
<mappingIncludes>**/*.class</mappingIncludes>
<verbose>true</verbose>
<enhancerName>ASM</enhancerName>
<api>JPA</api>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
After you execute %mvn package your deployable app will be in the folder target/guestbook. You should be able to deploy it and run it using the standard instructions for the Appengine Java SDK. I’m moving on to make sure I can run it in Intellij Idea. More on that later.
I’m still waiting for my Java account to activate at Google so I haven’t tried uploading the app yet.