November 17, 2010

Unit Testing Named Queues: Spring 3+maven2+Google App Engine

Intro
Problem, you have a task that you know can take more than 30 seconds to complete, what do you do?  What if this task needs to be triggered every day at a specific time?  Google provides several mechanisms to to solve just this problem, queues and scheduled task, respectively.

Queues
First, let's explore the "queue" system implemented in GAE.  Note, at this time, the "queue" is still experimental which means that the API can change around some, so make sure you have strong unit testing, but don't worry, we'll cover that a bit further down the page.  To implement queues, you need to let the web app know that your expecting queues to be used, and to do this, you need to create a file named queue.xml in your WEB-INF folder (example: /src/main/webapp/WEB-INF/queue.xml).  The queue.xml file has a specific layout and that will not be covered in depth in this post.  Please read up on the queue.xml structure on Google's documentation.  We will expand on the knowledge since the documentation is not complete.

Scheduled Task
Scheduled task are task that will trigger by GAE at repeatable times, emulating linux cron, or Quartz application.  To implement a cron task, simply create a file called cron.xml and place it in your WEB-INF folder (example:/src/main/webapp/WEB-INF/cron.xml).  This post will not go into detail on the implementation of scheduled task so please check Google's documentation to get a firm understanding before reading on. In order to not pack too much into one post, Scheduled Task will be covered in the next post.

Our Problem
The scenario we're going to explain is: You have an birthday tracking software and you want a user's friends to be notified, via email, that their friend is having a birthday.  Assume that the code for the services named are tested and fully working.

To solve this we will use a queue and the scheduled task system provided by Google App Engine.

First, let's tackle the queue portion, then we will create the scheduled task.  Google's documentation on unit testing queues is very limited and only shows how to retrieve the "default" queue.  Since we could have multiple task in our system that need to be run at different rates, we will want to create a new Queue.  Let's open (or create) the queue.xml file and insert the following:
<?xml version="1.0" encoding="UTF-8"?>
<queue-entries>
    <queue>
        <name>birthdayemail</name>
        <rate>10/s</rate>
        <bucket-size>10</bucket-size>
    </queue>
</queue-entries>


Next, let's create a simple service (Note: assume that the Autowired resources are working and imports are included at the top of the file, this has been reduced to emphasize the solution)

@Service("birthdayService")
public class BirthdayServiceImpl implements BirthdayService {

    // this is the same name as in your queue.xml file
    private static final String EVENT_REMINDER_TASK_NAME = "birthdayemail";
    
    @Autowired
    private BirthdayDAO birthdayDAO;

    public List handleGuestEmailsForBirthday(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("Date can not be null");
        }
        List<Guest> guestBirthdays = birthdayDAO.getByDate(date);
        for (Guest guest : guestBirthdays) {
            String TASK_URL = "/queue/birthday-emails/" + guest.getId()
            final TaskOptions taskOptions = TaskOptions.Builder.url(TASK_URL);
            // create a unique task name, note, must conform to [a-z] regex
            taskOptions.taskName(guest.getName() + "Task");
            taskOptions.method(TaskOptions.Method.POST);

            Queue queue = QueueFactory.getQueue(EVENT_REMINDER_TASK_NAME);
            // commented out to show the default queue shown in the docs
            //Queue queue = QueueFactory.getDefaultQueue();
            queue.add(taskOptions);
        }
        return events;
    }
}

Let's look at what's here:
First, we have to create a URL that will be run when the task is implemented. This URL will handle the unit of work specified, and should run in under 30 seconds per GAE's restrictions. We will not cover what this servlet does, just assume it uses the ID given in the URL path, pulls up the Guest, then uses that to get the Guest's friends' emails; then uses that to construct an email and pass to an EmailService. (HINT: the EmailService could also implement a queue so each email is separated out to run individually)

Next, notice that we are implementing a "Task Name". The this is optional, but does help when debugging to figure out what task is failing or what is running.

Now we're on to the TaskOptions. TaskOptions are a helper function used to combine URL and model data to pass on to the servlet handling the queue. Just a suggestion, but to follow the REST ideals, setting the RequestMethod to POST or PUT is advisable, depending on what you are trying to do. All Task should be idempotent, meaning that if the task fails or is interrupted, the task can be run again and not harm the data.

Lastly, we have the QueueFactory retrieving the Named Queue (the same name in the queue.xml file). Simply add your taskOptions object to the queue.add and move on.

Unit Testing Named Queues
Next, let's setup a unit test to test our named queue.  The Google documentation does not explicitly explain how to properly setup a test case for one, datastore aware context and named queries.  Below is an example of a test case written to test our Named Queries.  (Note, as before, imports have been removed and the services used have been used before.  This is not intended to be the end-all-be-all for unit testing GAE, please refer to previous post for more help, and yes, you might be able to use JMock or Mockito instead of persisting data, but I have not explored the option).

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/testApplicationContext.xml"})
public class QueueBirthdayServiceTest
        extends AbstractJUnit4SpringContextTests {

    @Autowired
    private BirthdayService birthdayService;
    private final LocalServiceTestConfig[] configs = {
        new LocalDatastoreServiceTestConfig(),
    /* NOTE: THE QUEUE XML PATH RELATIVE TO WEB APP ROOT, More info below */
        new LocalTaskQueueTestConfig()
                .setQueueXmlPath("src/test/resources/test-queue.xml")};
    private final LocalServiceTestHelper helper
            = new LocalServiceTestHelper(configs);

    @Before
    public void setUp() {
        helper.setUp();
    }

    @After
    public void tearDown() {
        helper.tearDown();
    }

    @Test
    public void testHandleBirthdayQueueEmails() throws InterruptedException {
        // setup data
        Date birtdayDate = DateUtils.parse("10/16/1900");
        // assume this builds the data for guest/guest's friends
        int guestWithBD = 5; // # of birthdays on date
        int gPerBirthday = 10; // # of emails being sent per birthday
        setupDataForBirthdays(birthdayDate, guestWithBD, gPerBirthday);

        List<Guest> birthdayOnDay = birthdayService.
                handleGuestEmailsForBirthday(birthdayDate);
        assertEquals(guestWithBD, birthdayOnDay.size());
        // pause for a moment to allow queue to fill from previous statment
        Thread.sleep(1000);
        // verify # of birthdays with that day's expire date
        LocalTaskQueue ltq = LocalTaskQueueTestConfig.getLocalTaskQueue();
        final Queue queue = QueueFactory
                .getQueue(BirthdayService.EVENT_REMINDER_TASK_NAME);
        //final Queue queue = QueueFactory.getDefaultQueue();
        QueueStateInfo qsi = ltq.getQueueStateInfo()
                .get(queue.getQueueName());
        assertNotNull(qsi);
        int expectedTaskCount = guestWithBD*gPerBirthday;
        assertEquals(expectedTaskCount, qsi.getTaskInfo().size());
        assertEquals(birthdayOnDay.get(0).getID() + "Task",
                qsi.getTaskInfo().get(0).getTaskName());

    }
}
NOTE: If the syntax or unit testing is very foreign to you, please visit my previous post on Unit Testing on Google App Engine.

Let's explore more
The first half is not too exiting, just setting up data and calling the service that creates the queue.  We are creating 5 guest with birthdays on the given date, and each of those 5 guest have 10 friends who we intend to email.  This service is already "written" out (above)

What you need to pay attention to is at the top of the file, during the setup of the "helper", we have constructed it with a LocalDatastoreServiceTestConfig and LocalTaskQueueTestConfig objects. The second, the "LocalTaskQueueTestConfig" is the important one to add when using a queue. If you are not using the DefaultQueue, you will need to explicitly state where the queue.xml file is. I suggest that you create a test-queue.xml file and place it in your /src/test/resources folder, so as to not mix production data and testing. NOTE: This file is loaded based relative to the ROOT application folder. The rest of the test should be pretty self explanatory.

In the next post, we will uncover how to wire the service up to a Scheduled Task so you can automate the emails being sent. Stay tuned!

September 15, 2010

Spring 3 + maven2 + Google App Engine: Part 6 [Integration Testing using HttpUnit]

In my previous post spring3 + maven2 + Google App Engine: Part 5[Unit Testing] I demonstrated how to create unit test for your Google App Engine application. Unit testing is only one part of the goal of 100% test coverage. The next major topic to cover, and arguably the most difficult to setup is integration tests. Integration test are test that use more than one component to complete the test. In web application testing, this is typically where test that can only be run when there is a running application server.

This post will cover Integration test using HttpUnit and the Failsafe Maven Plugin. Your first question is probably, why use failsafe in addition to the surefire. The quick answer is that the failsafe will continue if your servlets cause an exception allowing you to test all of your files.

Failsafe plugin
We'll get started adding the Failsafe plugin to the POM file. In your pom.xml file, add the following to your section:
<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <includes>
            <include>**/*SysTest.java</include>
        </includes>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
    </executions>
</plugin>

When the goal "integration-test" is run, the this testing plugin will include all files named SysTest.java. This should be changed to your specific package setup. Using "SysTest", "ITCase" or other pre/post fixes and separate packages are other options to segregate your integration test from your unit test.

Application Server
We now have the failsafe plugin, but we have to figure out how to run the application server before the integration test run. This is achieved by running the maven-gae-plugin, yes, the same plugin used to run your webapp. In recent releases of the maven-gae-plugin, developers added the stopPort and stopKey methods which allow failsafe to start and stop the application sever. The plugin can used the phases "pre-integration-test" and the "post-integration-test" to start and stop the GAE server.

Here is sample code to add to your pom.xml file inside of the section (typically right below the failsafe-plugin added above:
<plugin>
    <groupId>net.kindleit</groupId>
    <artifactId>maven-gae-plugin</artifactId>
    <version>0.7.1</version>
    <configuration>
        <scanIntervalSeconds>10</scanIntervalSeconds>
        <stopKey>STOP</stopKey>
        <stopPort>8005</stopPort>
    </configuration>
    <executions>
        <execution>
            <id>start-gae</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>start</goal>
            </goals>
            <configuration>
                <scanIntervalSeconds>0</scanIntervalSeconds>
                <daemon>true</daemon>
            </configuration>
        </execution>
        <execution>
            <id>stop-gae</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Notice, we are using the "start" verses using "run" because "start" does not include all of the task to "package" the war allowing the failsafe plugin to stop the GAE server.

Adding HttpUnit
In this posting, we will be adding and using HttpUnit as it's one of the most comprehensive and stable HTML unit testing libraries. HttpUnit not only allows you to query your URLs, but you can unit-test JavaScript, see errors for CSS, JavaScript and malformed HTML. HtmlUnit also allows you to emulate various different browsers including FireFox and Internet Explorer.

The integration test are very similar to the unit test buy using the same testing context file, Spring JUnit helper, Google Local Testing helpers and JUnit.

An integration test using HttpUnit
Here is a very basic example of an integration test:
package com.example.web.controllers;

...imports...

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/testApplicationContext.xml"})
public class HomeControllerSysTest extends AbstractJUnit4SpringContextTests {

    private static final Logger log = Logger.getLogger(
            HomeControllerSysTest.class.getName());
    private final LocalServiceTestHelper helper =
            new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    @Before
    public void setUp() {
        helper.setUp();
    }

    @After
    public void tearDown() {
        helper.tearDown();
    }

    @Test
    public void testHomeController() throws IOException {
        final String url = "http://localhost:8080/movie/test";

        final WebClient webClient = new WebClient();
        final HtmlPage page = webClient.getPage(url);
        assertEquals("The Page Title", page.getTitleText());

        // there are many different methods to query everything on your
        // page. Please refer to the HttpUnit homepage
        HtmlElement header = page.getElementsByTagName("h1").get(0);
        assertNotNull(header);

        String headerValue = header.getNodeValue();
        assertEquals(headerValue, "Hello World!");
    }
}

How to test
Now, it's time to run the test. There are several methods for running integration test without running the unit test, but those tactics will not be covered in this posting. To run the integration test, type the following:
mvn integration-test

That's it! Between this posting and the previous [Part 5] you should be able to test a large majority of your Java Web Application.

Spring 3 + maven2 + Google App Engine: Part 5 [Unit test]

Unit testing is one of the most important keystones to Agile programming methodologies. Testing with maven and Spring can be a big pain, so here's a quick tutorial on how to set it up. I will not cover proper testing strategies, but I'll give you the ability to setup your own testing.

First, we'll focus on unit testing. Unit testing is easily done using the "surefire plugin". To add the plugin, edit your pom.xml file, add the following inside of the section:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <includes>
            <include>**/*Test.java</include>
        </includes>
        <excludes>
            <exclude>**/*SysTest.java</exclude>
        </excludes>
    </configuration>
</plugin>

What this does is to tell Maven that during the phase "test", to run the JUnit test using the include/exclude rules.

Next we need to create a test file to run. Luckily we can use annotations to decorate our test files making it much easier. For this example, I will create a file in the test package called EventServiceTest.java.

package com.example;
...imports...
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/testApplicationContext.xml"})
public class EventServiceTest extends AbstractJUnit4SpringContextTests {

    @Autowired
    private EventService eventService;

    // Google's helper file to put all data storage in memory
    private final LocalServiceTestHelper helper =
            new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());

    @Before
    public void setUp() {
        helper.setUp();
    }

    @After
    public void tearDown() {
        helper.tearDown();
    }

    @Test
    public void testCreateEvent() {
        Event event = eventService.getByName("pie day");
        assertNotNull("Pie Day should always exist!", event);
    }
}

There are a few things to notice in this example. The LocalServiceTestHelper is a class provided by Google that will allow data to be stored in memory instead of interferring with your local datastore. There are several different types of configurations and customizations that can be passed into the constructor. Visit http://code.google.com/appengine/docs/java/tools/localunittesting/javadoc/ to check out other options.

If you noticed, we are loading a new context in the @ContextConfiguration annotation. You will need to create a new context file (similar to applicationContext.xml) which usually is a copy of the applicationContext.xml file, with changes to use mock services.

I choose to specify the context file by location, which is set in my POM file to be at /src/test/resources (refer to Part 2 to see full POM file). Another option could be to use classpath scanning.

Lastly, notice that the @RunWith(SpringJUnit4ClassRunner.class), this sets up the test file for class loading.

You can now run your unit test by running the following command:
mvn test

Next post will contain information about how to create and run integration test.

September 10, 2010

Spring 3 + maven2 + Google App Engine: Part 4 [Deployment]

Now you should have an easy application that is working and you'd like to deploy to Google's servers. Let's take a look at the appengine-web.xml file located in the project's /WEB-INF folder. This file contains all of the settings related to the appengine web application.

Here is an example appengine-web.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>my-unique-app-name</application>
    <!--  This variable is defined in your POM file -->
    <version>${gae.application.version}</version>
    <system-properties>
        <property name="java.util.logging.config.file" value="WEB-INF/classes/logging.properties"/>
    </system-properties>
    <sessions-enabled>true</sessions-enabled>
    <!--
    <static-files>
        <include path="/site/**" expiration="1d 12h" />
    </static-files>
    -->
</appengine-web-app>

Notice that the application node is filled out with your unique Google App Engine application name which was created during the creation of the application.

If you take a look at part 2 of this series which goes more in depth on the POM file, you will notice at the bottom of the file there are several properties/variables set. One of these is the application version, which correspond to the different versions you can deploy to Google's servers. Notice that in the POM file, there are several version setup using different profiles. When you deploy your application, you can setup different version numbers for testing, integration builds, staging or other required environments. The deployed version will follow the following URL format:

For a version of "0":
http://0.latest.your-unique-appengine-name.appspot.com/

For a version of "2":
http://2.latest.your-unique-appengine-name.appspot.com/

I recommend using the "0" version for testing, "1" for staging and "2" for production. This allows you to release to test and stage versions of your application, which will still use the same database, without releasing to production.

Now, onto how to deploy. If you have been following this series, you will be using the GAE plugin for Maven, which comes with many handy goals. Using the "gae:deploy" will deploy your application to the Google servers according to the appengine-web.xml file.

NOTE: I recommend creating batch files to deploy your application. Here is a very basic example of a bash script file:

#!/bin/bash
mvn gae:deploy -Dmaven.test.skip=true -Prelease-build

I have set the profile to "release-build" and decided to skip my test when doing my releases. Typically you will need to provide your email and password on the Google App Engine account to deploy.

Lastly, once your have a successful deployment, follow these directions.

  1. Check your application by using the URL format given above
  2. Once you have verified the version has been uploaded, goto http://www.appspot.com, login and goto your application's main page
  3. Look for "Application Versions" and goto those settings
  4. Select the "2" to be your version to be the "default"

Congratulations, you have the necessary skills to create an application using Google App Engine and Spring 3.0!

Later post will give more insights and tricks that I have learned while developing a full application exclusively hosted on Google App Engine.

April 8, 2010

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

This is a continuation of a multi-part series discussing how to get Spring 3 running on Google App Engine using maven.  This part discusses in more detail how to get Spring 3 MVC configured using annotations.

If you have ever had to setup a typical J2EE Web Application you remember (or perhaps have suppressed) the massive amounts of XML needed to configure your app.  Spring 2.5 took great steps towards reducing the use of XML by introducing annotation based configuration.  Annotation based configuration is probably the best achievement towards sustainable RAD.  For example, lets take your typical Spring web application.  You need a web.xml, dispatcher-servlet.xml, urlrewrite.xml (to have the greatest control of your URLs for SEO purposes), data-config xml files and a build.xml.  While you can not completely get rid of all of the XML, using annotations you can reduce the file size and best yet, remove dependencies to your business beans.

To start setting up your application with annotations, create a file called "dispatcher-servlet.xml" and place it in your WEB-INF folder.  This file will need to have several namespaces defined.

/src/main/webapp/WEB-INF/dispatcher-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

After saving the skeleton file above, it is time to add the meat of the configuration. First, we will tell Spring to wire Controllers to your POJOs that represent the "C" (controller) of MVC. In order to do this, we will need to place our controllers inside of a package structure so Spring can scan the package looking for the @Controller annotation. For our example, we setup our controller to be under com.example.web.controllers. Where you used to have to wire in a bean that used the class name to guess the controller, now we add the annotation to the class and that's it!

Add this to your dispatcher-servlet.xml file:
<context:component-scan base-package="com.example.web.controllers" />

That's it! Now we have the basics for setting up your first controller. Let's build our first Controller.  Create a file called HelloController.java under /src/main/java/com/example/web/controllers
package com.example.web.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.ui.ModelMap;

@Controller
public class HelloController {

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String helloGet(ModelMap map) {
        // this is your model (in future post, I will show how to use the ModelAttribute and command objects)
        map.put("name", "mike!");
        // for now, this is where your "View" is
        return "hello";
    }
}

For now, we will go with just the basics. Save this file and let's create the "View" so we you can run your application.

Create a file named hello.jsp and place it in /src/main/webapp/WEB-INF/jsp/views folder.
<%@ page contentType="text/html; charset=UTF-8" contentEncoding="UTF-8" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<-- it is recommended to take the preceding 
four lines and place them in a file to include on 
the top of each page -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Hello Controller</title>
    </head>
    <body>
        <h1>Hello ${name}!</h1>
    </body>
</html>

Lastly we must hook up our dispatcher servlet (front-loading servlet) so we can handle web request. Open /src/main/webapp/WEB-INF/web.xml file and add in the following:
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/movie/*</url-pattern>
</servlet-mapping>

Now we're ready to run our app!
mvn clean gae:run

NOTE: If this is the first time you have run Google App Engine application using Maven2, then type the following to "unpack" Google App Engine
mvn gae:unpack


Navigate to http://localhost:8080/movie/hello


Now that you have have checked out your first controller, you can already see things that are static and probably be changed. For example, take a look at your "helloGet" method. The String being returned points directly to the view. Rather than hard-code the entire path, we can setup a ViewResolver so you only need a small part of the view name.

Open /src/main/webapp/WEB-INF/dispatcher-servlet.xml and add in the following:
<bean id="viewResolver"
  class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  p:prefix="/WEB-INF/jsp/views/" 
  p:suffix=".jsp" 
  p:viewClass="org.springframework.web.servlet.view.JstlView"
  />

Now in your HelloController.java file, simply return "hello" (see how the strings concatenated together create the entire path?


You now have the basics of Spring MVC setup and so therefore this concludes this portion of the series on how to get Spring and Maven2 running on Google App Engine

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

April 1, 2010

Spring 3 + maven2 + Google App Engine: Part 1 [Initial Project Setup]

Recently a co-worker started down the path of Spring 3, Spring MVC and Google App Engine. After hearing him talk about it, I decided it was time for me to figure out what the hype was and figure out how to program something using the "cloud".

This series of post will discuss one approach to getting my favorite Java web-app stack of Spring 3, Spring MVC (both with annotations), maven2 and all developed on Google App Engine.  Since unit testing is a corner stone of Agile development, JUnit test will also be included to show how to test your code prior to deployment to GAE servers.

This series assumes that you have and know how to use the following: Google login (Gmail or iGoogle for example), Java 1.6, some IDE (Eclipse, NetBeans, InteliJ, Notepad++, etc) though you do not need to install the suggested "Plugins", maven2, Ant 1.7+, web browser, command line

We will be building a simple "Movie Listing" web application where you can enter a movie, add a comment (single user, for now), add "Actors" to that movie. The model and idea is very simple and easy to define so we can focus on the technology.

Step 1: Sign up for a Google App Engine
First off, you will need to sign up for a Google App Engine account before you can do anything else.  Visit http://code.google.com/appengine/ and click on "Sign Up" under "Getting Started" on the right side navigation.

Note: Remember the URL you fill out as the name of your application, this will be used later in the POM file


Step 2: Setup the project
Once you have your GAE account setup, you need to setup your web application. 

Suggested directory structure and project layout:
pom.xml
src
    - main
        - resources
        - site
            - img
            - javascript
            - css
        - webapp
            - WEB-INF
        - java
            - com
                - example
                    - controllers
    - test
        - resources
        - java
            - com
                - example
                    - controllers

This is just a standard Spring Web App, nothing special here.  As a shortcut, you can use the maven command: (this will create most of the folder structure and default files)

mvn archetype:create -DgroupId=com.example.app -DartifactId=movie-app -DarchetypeArtifactId=maven-archetype-webapp

At this point, you should be able to "clean" and "install" the application.  Nothing will happen since we have not setup the project, which is in the next post.

Run the project with:

mvn clean install

Depending on how your maven usage, different plugins may need to download but ultimately you should see "Build Successful" in the output.