April 6, 2010

Spring 3 + maven2 + Google App Engine: Part 2 [POM Setup]

In this post, we will look at the POM file and the dependencies for not only a solid web application using Spring 3, but the dependencies specific to Google App Engine. This is not meant to be a comprehensive overview of Maven and may or may not use best practices for Maven (ie, I'll ignore comments about your maven file, grab a maven book, hopefully off the links to the right!)

Now, let's take a look at the POM file and setup our project.  We need to add the Google App Engine and the related dependencies, DataNucleus for enhancing domain objects (though, I am investigating how to use Spring persistence through Annotations to replace this dependency), JUnit and various other utilities needed to construct a working web-app.

Most of the POM file generated from part 1 will be sufficient, but we need to start adding dependencies. We'll start with the Spring 3.

Inside of your <dependencies> section, lets add the following dependencies:

Project Dependencies

Spring 3
 
        <dependency>
            <groupid>org.springframework</groupid>
            <artifactid>spring-webmvc</artifactid>
            <version>3.0.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupid>org.springframework</groupid>
            <artifactid>spring-test</artifactid>
            <version>3.0.1.RELEASE</version>
        </dependency>

Google App Engine
 
        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>datanucleus-jpa</artifactId>
            <version>1.1.5</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>geronimo-jpa_3.0_spec</artifactId>
            <version>1.1.1</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-1.0-sdk</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-labs</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-api-stubs</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-testing</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.google.appengine</groupId>
            <artifactId>appengine-local-runtime</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>


Google App Engine Data Store
 
        <dependency>
            <groupId>javax.jdo</groupId>
            <artifactId>jdo2-api</artifactId>
            <version>2.3-eb</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.transaction</groupId>
                    <artifactId>transaction-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <type>jar</type>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>

        <dependency>
            <groupId>com.google.appengine.orm</groupId>
            <artifactId>datanucleus-appengine</artifactId>
            <version>1.0.5.final</version>
        </dependency>

        <dependency>
            <groupId>org.datanucleus</groupId>
            <artifactId>datanucleus-core</artifactId>
            <version>1.1.5</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.transaction</groupId>
                    <artifactId>transaction-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

Now you have the default minimum dependencies for GAE (still not there quite yet, we need to add the necessary plugins). If you are more familiar with Maven, you might want to add in Ant, Apache Commons Collections and any other libraries you typically use.

Plugins
Once you have the needed libraries it is time to setup the plugins to build and run your project.  Add the following to the section:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1-alpha-2</version>
    <configuration>
        <webAppConfig>
            <contextPath>/movie</contextPath>
            <scanIntervalSeconds>10</scanIntervalSeconds>
        </webAppConfig>
        <webResources>
            <resource>
                <directory>src/main/webapp</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/appengine-web.xml</include>
                </includes>
            </resource>
        </webResources>
    </configuration>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.6</source>
        <target>1.6</target>
    </configuration>
</plugin>

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <version>${cobertura-version}</version>
    <executions>
        <execution>
            <goals>
                <goal>clean</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.datanucleus</groupId>
    <artifactId>maven-datanucleus-plugin</artifactId>
    <version>1.1.4</version>
    <configuration>
        <!-- Make sure this path contains your persistent classes! -->
        <mappingIncludes>**/model/*.class</mappingIncludes>
        <!-- */This is where your domain objects will be located -->
        <verbose>true</verbose>
        <enhancerName>ASM</enhancerName>
        <api>JDO</api>
    </configuration>
    <executions>
        <execution>
            <phase>compile</phase>
            <goals>
                <goal>enhance</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.datanucleus</groupId>
            <artifactId>datanucleus-core</artifactId>
            <version>1.1.5</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.transaction</groupId>
                    <artifactId>transaction-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.datanucleus</groupId>
            <artifactId>datanucleus-rdbms</artifactId>
            <version>1.1.5</version>
        </dependency>
        <dependency>
            <groupId>org.datanucleus</groupId>
            <artifactId>datanucleus-enhancer</artifactId>
            <version>1.1.4</version>
        </dependency>
    </dependencies>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven-surefire-plugin-version}</version>
    <configuration>
        <includes>
            <include>**/*Spec.java</include>
            <include>**/*Test.java</include>
        </includes>
    </configuration>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jxr-plugin</artifactId>
</plugin>

<plugin>
    <groupId>net.kindleit</groupId>
    <artifactId>maven-gae-plugin</artifactId>
    <version>0.5.2</version>
    <configuration>
        <unpackVersion>1.3.2</unpackVersion>
    </configuration>
</plugin>

<plugin>
    <artifactId>maven-release-plugin</artifactId>
    <configuration>
        <goals>gae:deploy</goals>
    </configuration>
</plugin>

<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
        <execution>
            <phase>compile</phase>
            <configuration>
                <tasks>

                    <!--
                        This creates the META-INF folder inside of classes, then
                        copies over the jdoconfig.xml required for GAE
                    -->
                    <mkdir dir="${project.build.directory}/classes/META-INF"/>
                    <copy file="${project.build.directory}/classes/jdoconfig.xml"
                          todir="${project.build.directory}/classes/META-INF" />
                    <echo message="Copy:${project.build.directory}/classes/jdoconfig.xml to " />
                    <echo message="${project.build.directory}/classes/META-INF"/>
                </tasks>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
</plugin>


Click here to get the full pom.xml file

5 comments:

Paul Zain said...

Nice article, but I would really like to see your entire pom file. The link you posted doesn't work as I keep getting redirected to the blogger.com login page (even after I login). Thanks!

Mike! said...

Hey Paul,

thanks for pointing that out! I didn't realize that the link was not working. I have made a small modification to the POM file from above. I took out "jetty" since it was not being used (use gae plugin instead)

Mike!

Gonzalo Diaz said...

Hey Mike, great blog.

I just want to mention that I am having issues following this steps. Once I have everything set, the command
mvn clean install
throws this message


[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] An Ant BuildException has occured: Warning: Could not find file /home/gdiaz/Documentos/development/workspace-appengine/peditudelivery/target/classes/jdoconfig.xml to copy.

Should I create jdoconfig.xml file? Where should I create it?

Thanks!
Gonzalo.

Mike! said...

Hey Gonzalo,

I didn't publish all of my files so there might be a few things incorrect, but I'll try to answer all the questions I can in comments. To your comment, you need to create a file called "jdoconfig.xml" in your WEB-INF folder. This is your configuration for all of your JDO object. To find out more, the documentation that Google gives on JDO setup is pretty comprehensive.

Mike!

Sean said...

I had to add the Maven Google App Engine Repository to my POM to make this work:


maven-gae-plugin-repo
Maven Google App Engine Repository
http://maven-gae-plugin.googlecode.com/svn/repository/