Jul 13, 2009
Grails and Google AppEngine
I have recently started a new project and I decided based on some of the application requirements and its rapid development that I would host it at Google AppEngine. For a web framework I went with Grails due to the rapid prototyping that it makes possible.
I can’t really go to much into the functionality of the app, however I thought I would share some of the experiences I’ve had building the application in the Google environment with Grails. First off, if you are going to be doing any serious work with Grails then you’ll need to get a copy of Intellij, the experience developing with it is much better than others I tried (and improving even more in the 9.0M1 release). The initial cut of the application was written using GORM and against a local database, however after trying GORM-JPA (it is very early still though moving quickly), I decided that trying to take a RDBMS mapping over to AppEngine datastore was not going to be a productive route. The first real lesson of AppEngine is understanding the data store, it is strange but several of the applications I have worked on over the past 4-5 years have started to move away from traditional RDBMS. I’m not about to get into the NoSQL argument, other than to say ultimately you need to sit down and understand the tools that are available. AppEngine DataStore is a powerful storage engine (I’m purposefully not calling it a database), though it does take a little getting used to. If you are planning to take a look I would start with the recent Google IO presentation by Max Ross.
Since I have been working with HBase lately some of the concepts weren’t so alien, however it I did find that using JPA annotations actually lead me into incorrect thinking at times, while adding the annotations I was immediately thinking in the RDBMS mapping terms. Since I wanted to use the JPA annotations, but didn’t feel that GORM-JPA was quite ready I switched over and used the Grails JPA plugin, in some ways this meant creating a DAO to allow me to interact with the store. In the end I did this through the creation of a service which I used in the controllers, it was pretty generic thanks to the nature of groovy – in the end I can see myself probably moving back to GORM later on, though in the meantime having a closer relationship with the JPA interface allowed me to better understand how relationships were being managed by AppEngine. GORM has a tendency to abstract you a little to much at times and coming to terms with a new type of storage engine means that abstraction leads to another level of indirection. I can see that as time passes and the ins and outs of AppEngine Datastore become more like second nature then that indirection is something that is easy to handle, though at the beginning I think it is easier to get used to the datastore without it there.
Plugins is one of the powerful aspects of Grails, however one of the problems you encounter in the AppEngine world is the file limit (currently 3,000). While adding a lot of UI plugins speeds up development you can quickly find that you have blown the file limit. Also make sure you watch the $USER_HOME/grails/1.1.1/projects/{yourproject}/stage directory, if you start removing things from your application (ie. unneeded JS) then you might well find that they are remaining in the stage directory.
If you are using YUI you can switch to their servers, so that you don’t have to hold all the YUI files, first add the following to your BootStrap:
def init = {servletContext ->
JavascriptTagLib.LIBRARY_MAPPINGS.yui = []
}
Then in your main.gsp make sure you reference the CSS and JavaScript you need.
If you are using the grails-ui plugin 1.0.4 it is currently using the javax.rmi.UID class to generate UUIDs, this class is blacklisted by GAE/J and therefore you would need to change the GrailsUITagLibService.groovy and remove the import. I found that I was able to use the UUID class to get a similar effect (see JIRA)
def getUniqueId = { 'gui_' + DigestUtils.md5Hex(UUID.randomUUID().toString()) }
Once you have the basics in place, then you will need security. Obviously Google provides API’s to allow this to exist, however often you need more complex security than is currently provided by the Google API. In Grails I naturally jumped for the Aecgi plugin, however after a few battles with its close connection with Hibernate (I get the feeling that plugin does a little too much and would be well served by being broken up into a several plugins rather than a lot of configuration in one plugin). Next up was Stark Security plugin – I have to admit it was a little new to me, however I was able to quickly implement this in grails and also get it functioning in GAE/J. Basically I needed to create the basic DAO stuff using the plugin then change it to use JPA methods (as seen below):
User.groovy
import org.datanucleus.jpa.annotations.Extension
import org.springframework.security.GrantedAuthority
import org.springframework.security.userdetails.UserDetails
import javax.persistence.*
/**
* This class is the default UserDetails implementation for the Stark Security plugin.
* Since instances of this class will be used by the underlying Spring Security framework across
* Hibernate sessions, we can't have any lazy loading in here (see special handling of roles below).
*/
@Entity
class User implements UserDetails {
@Id
@GeneratedValue (strategy = GenerationType.IDENTITY)
@Extension (vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
String id
@Column
String username
@Column
String password
List<String> roles = new ArrayList<String>();
GrantedAuthority[] getAuthorities() {
return roles.collect { new Role(authority:it) } as GrantedAuthority[]
}
boolean isAccountNonLocked() {
return true
}
def setAccountNonLocked(boolean nonLocked) {}
boolean isCredentialsNonExpired() {
return true
}
def setCredentialsNonExpired(boolean nonExpired) {}
boolean isAccountNonExpired() {
return true
}
def setAccountNonExpired(boolean acctNonExpired) {}
boolean isEnabled() {
return true
}
def setEnabled(boolean enabled) {}
}
Role.groovy
class Role implements GrantedAuthority {
String authority
static final ANONYMOUS = 'IS_AUTHENTICATED_ANONYMOUSLY'
// Add your roles here so you can reference them, for instance:
static final ADMIN = 'ROLE_ADMIN_USER'
// This list holds all roles, convenient when you're declaring controller methods
// that should be available to everybody (see AccessController for instance). When
// you add roles to your system, make sure you add them to this list as well.
static final ALL_ROLES = [ANONYMOUS,ADMIN]
int compareTo(Object o) {
if (o instanceof Role) {
return this.authority.compareTo(o.authority)
}
return 0
}
String toString() {
return authority
}
}
Also once in AppEngine it is a little more sensitve to reflection, with the standard plugin I got:
java.lang.IllegalAccessException: Reflection is not allowed on private int java.util.ArrayList.size
This was down to line 217 of the StarkSecurityGrailsPlugin.groovy having:
if (authFilters.size < 1) {
When it should have been
if (authFilters.size() < 1) {
I opened a JIRA for this one. Also you might find that plugins embed javascript (such as the Grails UI plugin), in which case you will want to change the StarkSecurityConfig.groovy to allow access to these files:
authorizations = [ '/': Role.ALL_ROLES, '/js/**': Role.ALL_ROLES, '/css/**': Role.ALL_ROLES, '/images/**': Role.ALL_ROLES, '/plugins/**': Role.ALL_ROLES, '/j_acegi_logout': Role.ALL_ROLES ]
Another problem was changing the log4j not to write to the file system (you’ll get a restricted class exception). This is done with:
'null' name:'stacktrace'
While building the system up, I also discovered the problems of not setting the seralizationUIDs on classes that might end up in session (ie. Role), make sure you set it on the class or you will need to flush you local cookies after deployment.
Also I found a nasty little problem in the formRemote tag, basically it would operate in the development server but not on AppEngine itself, in the end I dug around I found that the JavascriptTagLib.groovy made some assumptions about a variable being a map which it wasn’t (in fact it was a String in this case). Due to Groovy’s ability to reflect private values (which just feels dangerous), you would end up with:
<span>[deve11/5.334872088869876828]</span>.<stderr>: java.lang.SecurityException: java.lang.IllegalAccessException: Reflection is not allowed on private final char[] java.lang.String.value
I ended up having to pull the JavascriptTagLib.groovy into the project and make the fix there, and opened another JIRA in grails for it.
So there it is – a brief little walkthrough getting Grails operating in Google AppEngine. GAE/J feels a little clunky at times and it probably does suffer from being a little rushed out of the door. However, after you start to get your head around the restrictions it does start to become a good platform. Over time I’m sure we are going to see further improvements in the Google Platform, and while I am still working with the Amazon style Infrastructure as s Service world starting to look more closely at Platform as a Service has opened my eyes to some of its benefits. The days of managing your database and server could soon be gone – though I think it will be a specific type of application that benefits most.





Dear Philip,
Thanks for the written suck a great post regarding Grails on GAE.
I tried to make stark security works in my grails application on GAE.
But I stuck in setting up OneToMany relationship of User and Role class.
FYI, I am using app-engine, gorm-jpa and stark-security plugin in my grails application.
Did you published your source code of this post, so that I can access it via an URL?
Any pointer will be appreciated.
Thanks
Hey Chee
Actually I cheated on that bit since I just store a list of roles
List roles = new ArrayList ();
On the user and the role actually doesn’t persist therefore I don’t need to worry about the relationship. Though you should be able to get a one to many relationship working – you need to remember that it is all done through the annotations and the normal GORM notation (like hasMany) is not used by GORM-JPA.
Hope that helps – if not comment again and I can e-mail you and take a look :)
Cheers
P
Hi Philip,
Thanks for fast response.
Yes. I am awared that GORM mapping (like hasMany) is not supported by gorm-jpa plugin, so all the mapping I did is using JPA annotations. Thanks for information and reminder. But still no luck, I am unable to make it works.
I sent a post to StackOverflow for detail description about problem I faced:
http://stackoverflow.com/questions/1377091/how-to-setup-one-to-many-unidirectional-mapping-for-grails-application-on-gae
It will be great if you can have a look there and advise further.
Thanks.
Great post Philip,
Helping me move forward on a similar simple GAE Grails app and need a very simple security solution and trying to get Stark Security going. Would you mind posting what you did with the Stark Security UserLookupService.groovy service? I’m currently getting this error when logging in:
Error 500: Class User for query has not been resolved. Check the query and any imports specification
And the one other thing, if you could please post what you did within your BootStrap.groovy to get your initial user/role established.
Again, thanks a bunch for posting what you have to this point. Very helpful.
@chadsmall
Hey Philip,
Back with an update. Further, but spinning on this one a bit. Maybe you can shed some light? I think you got past this somehow?
I changed this line in UserLookupService.groovy:
//User user = User.findByUsername(userName) //this doesn’t work?
User user = User.findWhere(username: userName)
and this is my BootStrap.groovy to seed a user:
def adminUser = new User(username: ‘admin’, password: PasswordEncoder.encode(‘password’, ‘SHA-256′, true), roles: ['ROLE_ADMIN_USER'])
adminUser.save()
I startup the app with no errors (not sure how to verify my save user happened on bootstrap). App directs me to the login page and when I attempt admin/password login, I get this exception:
javax.jdo.JDODetachedFieldAccessException: You have just attempted to access field “roles” yet this field was not detached when you detached the object. Either dont access this field, or detach it when detaching the object.
at com.thesmallcompany.triangleadmin.User.jdoGetroles(User.groovy)
at com.thesmallcompany.triangleadmin.User.getAuthorities(User.groovy:34)
Seems like a pretty good error message and I’ve looked around, but being a JPA newbie, not sure how to ‘detach’ the object :) Assume the bootstrap save() is somehow not ‘detaching’??
Here is the code (same as you have in your post above) that it doesn’t like:
GrantedAuthority[] getAuthorities() {
return roles.collect { new Role(authority:it) } as GrantedAuthority[] //line 34
}
thanks bunches for anything,
@chadsmall
Hey Chad
It sounds like you are having a problem the session, the actual code I put up there shouldn’t really have this problem since the Role object is never actually persisted in the datastore, it is simply a list of strings held in the user entity.
Looks like you are using GORM-JPA?
Cheers
P
Thanks for the response Philip. Yeah, I’m using GORM-JPA (grails plugin) for only the User class, just like you were doing (and not the Role class) – copied your User & Role code verbatim. Just to get around the error in my previous comment, I hard coded the User.getAuthorities() like this and got by the error – but long term, I can’t hard code every user to ADMIN :)
GrantedAuthority[] getAuthorities() {
//return roles.collect { new Role(authority:it) } as GrantedAuthority[] //this doesn’t work – get javax.jdo.JDODetachedFieldAccessException
return [new Role(authority:'ROLE_ADMIN_USER')] as GrantedAuthority[]
}
Were you able to get the
roles.collect { new Role(authority:it) } as GrantedAuthority[]
to work? You still have code around for your UserLookupService.groovy & BootStrap.groovy?
thanks,
@chadsmall
Just sent over an e-mail with some more details – happy to keep trying to help :)