Skip to content

ninjaframework/ninja-appengine

Repository files navigation

 _______  .___ _______        ____.  _____   
 \      \ |   |\      \      |    | /  _  \  
 /   |   \|   |/   |   \     |    |/  /_\  \ 
/    |    \   /    |    \/\__|    /    |    \
\____|__  /___\____|__  /\________\____|__  /
     web\/framework   \/                  \/ 

Google App Engine support for Ninja

This module allows to use Ninja on the GAE easily.

In particular it provides:

  • Objectify to store data.
  • The default Mailer.
  • Everything else is absolutely standard Ninja.

Usage

ninja-appengine is released along with the GAE SDK. Therefore we use the same version. For instance ninja-appengine 1.9.88 uses SDK 1.9.88.

Usage is straight forward. The most important thing you have to keep in mind is to annotate your controller classes with @FilterWith(AppEngineFilter.class)

@FilterWith(AppEngineFilter.class)
public class MyController {
    ...
}

If you cannot use @FilterWith because you are developing a library you can also use annotation @AppEngineEnvironment on classes or methods. But you should prefer using @FilterWith.

This is needed to setup the dev environment. If you forget this you'll get a lot of strange error messages especially in tests.

When using persistence you have to register your objectify models. Please refer to https://github.com/objectify/objectify/wiki/BestPractices Of Service for some best practises.

In Ninja's context it is best to create a Guice Provider. That we you are able to inject Objectify into your classes. We usually put the class under conf.ObjectifyProvider:

public class ObjectifyProvider implements Provider<Objectify> {

    static {
        factory().register(Model1.class);
        factory().register(Model2.class);
        ...etc
    }

    @Override
    public Objectify get() {
        return ObjectifyService.ofy();
    }

}

You then have to bind your Provider in your conf.Module class:

public class Module extends AbstractModule {


    protected void configure() {

        // bind your Objectify.class to your provider like so:
        bind(Objectify.class).toProvider(ObjectifyProvider.class);

        install(new AppEngineModule());        

    }

}

More about Objectify: https://github.com/objectify/objectify

Quick start

Generate a Ninja Appengine archetype by calling the following command:

mvn archetype:generate -DarchetypeGroupId=org.ninjaframework -DarchetypeArtifactId=ninja-appengine-blog-archetype

This will generate a full archetype showing a simple blog complete with Objectify as persistence layer. A nice archetype to start your own projects...

Deployment

Is as easy as:

mvn clean appengine:update -Pupdate

Starting

Use the devserver of GAE:

mvn appengine:devserver -Pdevserver

Testing

When your tests extend NinjaTest you can just start right away. Initialization of the test env is done via the filter you used for your controllers. The tests use an in-memory implementation of the datastore.

Basic Setup

First of all have a look at the demo application at: https://github.com/reyez/ninja-appengine/tree/master/ninja-appengine-blog-integration-test

The demo application show best how to setup

  • pom.xml
  • application.conf
  • appengine-web.xml

pom.xml

  1. Add the dependency to your pom:

    org.ninjaframework ninja-appengine-module 1.9.88
  2. Add profiles for production / development to your pom:

The easiest way is to go to

https://github.com/reyez/ninja-appengine/blob/master/ninja-appengine-blog-integration-test/pom.xml

and copy the relevant parts to your project. In short you have to:

  • Have profiles for "update", "devserver" and "jetty-dev".
  • Configure the appengine libraries with the correct scopes
  • Set the build output dir consistently

It is also important to filter the resources to finally set the mode dev / production:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <webResources>
            <webResource>
                <directory>${basedir}/src/main/webapp/WEB-INF</directory>
                <includes>
                    <include>**/*</include>
                </includes>
                <targetPath>WEB-INF</targetPath>
                <filtering>true</filtering>
            </webResource>
        </webResources>
    </configuration>
</plugin>

appengine-web.xml

The Appengine xml is pretty default. The only difference is that we are setting the Ninja mode via a system property. Now the whole process inside the pom.xml makes more sense I guess :) ${ninja.mode} is simply the variable getting exchanged with "prod" in case of the update profile and "dev" else...

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">

    <application>myappid</application>
    <version>myappversion</version>

    <static-files>
        <include path="/static/**" />
    </static-files>

    <threadsafe>true</threadsafe>

    <!-- will be set to "prod" when running mvn with profile update -->
    <!-- eg: mvn install appengine:update -Pupdate -->
    <system-properties>
        <property name="ninja.mode" value="${ninja.mode}" />
    </system-properties>

</appengine-web-app>

Special configuration variables in application.conf

(If you are using the default Ninja AppEngine archetype there is nothing you have to set up)

  • cache.implementation=ninja.appengine.AppEngineCacheImpl Tells Ninja to use the GAE built in cache.
  • postoffice.implementation=ninja.appengine.AppEnginePostofficeImpl Tells Ninja to use GAE to send mails.