Login required
Download

Grails AppEngine plugin

(18)
Author(s): Graeme Rocher
Current Release: 0.8.9
Grails Version: 1.2 > *
Tags cloud deployment google
To install type:

grails install-plugin app-engine

Overview

This plugin integrates the Google AppEngine SDK and deployment tools with Grails.

If you are having trouble with the plugin click the 'Faq' tab above as it may have your answer

You need to tell it where your SDK is by setting APPENGINE_HOME or specifying "google.appengine.sdk" in BuildConfig.groovy.

The plugin adds the appengine SDK classes onto your classpath and packages them as part of the WAR, meaning you can reference com.google.appengine.api.* packges.

To run the development environment and upload there is an app-engine script:

grails run-app // run the dev environment on port 8080
grails -Dappengine.debug=true run-app // run the dev environment in a debug JVM on port 9999
grails app-engine deploy // deploy your app
grails app-engine rollback // rollback last update
grails app-engine logs --file=logs.txt --days=10

Screencast

Checkout this screencast for an introduction.

The screencast is slightly out of date so make sure to follow the documentation and not the screencast when trying the plugin

Step-by-Step Process

1) Register for a Google AppEngine Account

This can be done at http://appengine.google.com

2) Download and install Grails 1.2 or above

You can grab Grails from the Download page

3) Create a Grails Project

grails create-app first-app
cd first-app

4) Match the Grails application name with the Google application

In the AppEngine web interface create an application that matches your Grails application name. If this is not possible create any name and then set the AppEngine application idenfier in Config.groovy:

google.appengine.application="petclinic-grails"

5) Install the AppEngine plugin

grails install-plugin app-engine

When prompted choose 'JPA' as the option for persistence. Then install the GORM-JPA plugin:

grails install-plugin gorm-jpa

6) Run the application

Start up the application by typing the following:

grails run-app

This will start the AppEngine development environment on port 8080.

If you get an exception or are having problem make sure you don't have the tomcat or jetty plugins installed as well:

grails uninstall-plugin tomcat

7) Deploy the application

grails set-version 1
grails app-engine package

You then need to run the command:

$APPENGINE_HOME/bin/appcfg.sh update ./target/war

on MacOS and Linux or

%APPENGINE_HOME%/bin/appcfg.cmd update ./target/war

on MS Windows or

$APPENGINE_HOME/bin/appcfg.cmd update ./target/war

on Cygwin.

Persistence

The plugin will currently install support for either JDO or JPA based persistence into a Grails application.

In the case of JDO a grails-app/conf/jdo-config.xml file is installed into the project when the plugin is installed.

The plugin also automatically configures a Spring JdoTemplate which you can use to interact with JDO using Spring:

def jdoTemplate

In the case of JPA a grails-app/conf/persistence.xml file is installed instead.

The plugin also automatically configures a Spring JpaTemplate which you can use to interact with JPA using Spring:

def jpaTemplate

For example:

def jpaTemplate
def transactionTemplate
def save = {
   transactionTemplate.execute( { status ->	
        def album = new Album(params)
	if(!album.hasErrors() && album.validate() ) {
		jpaTemplate.persist(album)
		jpaTemplate.flush()
		flash.message = "Album ${albumInstance.id} created"
		redirect(action:show,id:album.id)	
	}
	else {
		status.setRollbackOnly()				
		render(view:'create',model:[album:album])				
	}

} as TransactionCallback ) }

Persistent classes can be placed in the grails-app/domain directory. The plugin will automatically enhance them using the DataNucleus tools.

Domain classes MUST be placed in packages otherwise Google's command line tools don't work!

To get GORM-like behavior with dynamic finders and so on you need to install the GORM-JPA plugin (there currently isn't a GORM API for JDO, sorry!):

grails install-plugin gorm-jpa

Once this is installed you can using of the regular methods provided by the GORM API like save(), delete() and so on as well as dynamic finders.

Authentication

You can use Google's authentication by configuring the following properties in grails-app/conf/Config.groovy

google.appengine.sessionEnabled = true // default true
google.appengine.enableSsl = true // default true
google.appengine.security.useHttps = ["/secure", "/shoppingcart/*", "/admin"]
google.appengine.security.requireAdmin = ["/admin", "/notsecuredadmin"]
google.appengine.security.requireLogin = ["/admin", "/", "/yabbadabbadoo"]

Examples

There is currently an example Grails on AppEngine application that is a port of the Grails petclinic sample running at http://petclinic-grails.appspot.com/

The source code can be found in Github at http://github.com/grails/grails/tree/c4d2c6e96708ae6ee15f2ac8cef1448052189ab3/grails/samples/petclinic-appengine

Version History

  • 0.8.7 - Now possible to use standard run-app command and fixed Log4j errors
  • 0.8.5 - Testing classes corrections.
  • 0.8.4 - Refactorized how to access to Persistence or Entity Manager Factory. Added some basic capabilities to unit tests appengine related logic.
  • 0.8.3 - Fixes NamingException when using JPA, duplicate EntityManagerFactory error and correctly deploys using production environment settings
  • 0.8.2 - Added support for authentication configuration, OpenEntityManagerInView/OpenPersistenceManagerInView support and fixed datastore-index bug
  • 0.8.1 - Fixed 'grails app-engine log' command, improved authentication, added better error handling when running 'grails run-app'
  • 0.8 - Added support for JPA persistence, fixes generate-all bug and automatically uninstalls hibernate plugin on install
  • 0.7 - First official release

Bugs

It is true that there are some bugs with this plugin, but most have a solution at this time.

Example: The "DataNucleus Enhancer prevents application from building on Windows OS due to path length exceeding max path length on Windows." - However, there is a work-around for Windows and this wont stop use of the plugin.

This is great news! As you say that there is a work-around for Windows would you please publish that work-around for Windows here so that those using Windows and are experiencing this problem can benefit from that information?

For mor information regarding workarounds on windows there is a writeup here: Google AppEngine on Windows

FAQ

Versioning

Google AppEngine expects non-decimal version numbers, whilst Grails' versioning system starts at 0.1. To get around this you should use non-decimal version numbers:

grails set-version 1

Permissions

The current preview release of the Google AppEngine SDK has a bug that doesn't allow it to run Groovy code when the full permissions restrictions are used. This will be fixed in the next release, but in the meantime the development environment runs without emulating the permissions restrictions of the actual AppEngine environment.

Index Creation

AppEngine requires that you specify indexes. By default Grails installs a grails-app/conf/datastore-index.xml file into your application that is set to auto-generate indexes during development.

However, realistically you should be manually managing your indexes as per these instructions. If you don't you may get exceptions in production that don't occur in development.

Static Resources

AppEngine has a bug in it that means it incorrectly deals with <welcome-file-list> definitions. In order to workaround this the app-engine plugin automatically installs a modified src/templates/war/web.xml file that removes the <welcome-file-list> definition.

Domain Classes

You must place domain classes into a package (i.e. not the default package), otherwise grails will complain that it 'could not resolve class for query'.

Inability to obtain ID after a save with gorm-jpa Plugin

If you are using the dynamic or static scaffolding of controllers with gorm-jpa, you will get a null pointer exception on saving an object if you immediately attempt to redirect to show it (as the scaffolded controller does). You need to add flush:true to your save to have immediate access to the ID. This is fully explained in JIRA bug 1375

Checkout this screencast for an introduction.