web page hit counter

Thursday, July 02, 2009

Popstat on Google App Engine

Popstat is the demo application from my Facebook Dev Garage Dallas presentation. It just posts a status message to Facebook and Twitter to demonstrate using both Facebook Connect and an external service. I developed it on my laptop and didn't have time to move it to a public host before the event. I wanted it out there live someplace and figured it was a good opportunity to try out Google App Engine's Java support (Popstat uses Grails with a mix of Groovy and Java)

I got it all working, but it was a pain.
  • I used the Grails AppEngine plugin. I liked it.
  • App Engine provides storage, but not in the form of a relational database. It's close enough that JPA and JDO both work (but not Hibernate, yet). I chose JPA, but either way you'll need to annotate your domain classes (I expected the GORM-JPA plugin to do that for me, but it didn't)
  • You'll need to put your domain classes into named packages. Things (silently) don't go well if you leave them in the default package.
  • If you're using JPA, domain classes will need to explicitly declare an id field. Make it a Long, and add the @Id and @GeneratedValue annotations. Use GenerationType.IDENTITY.
  • I was able to use the dynamic save() method provided by GORM-JPA, but I had to wrap up the calls in a withTransaction block, and the semantics are slightly different (use merge() instead of save() for updates)
  • Depending on your version of Spring, you may get a message along the lines of "org.springframework. context.annotation. internalPersistenceAnnotationProcessor': Initialization of bean failed" with something about "java.lang.NoClassDefFoundError: javax/naming/NamingException". The fix here worked for me.
  • Popstat uses the facebook-java-api library. Since App Engine forbids the use of JAXB, I had to switch to the JSON version of the client to avoid an error about JAXBContext.
  • To talk to Twitter, Popstat uses the oauth-signpost library. But Signpost depends on Apache HttpClient, and HttpClient uses low-level Socket calls forbidden by App Engine. I hacked Signpost to use URLConnection, but I wouldn't recommend that approach. If I had to do it again, I'd look around for an OAuth library that worked out of the box.
  • By default, the App Engine Java Development Server (a version of the App Engine environment you can run on your local machine) binds to localhost only. The command line client has a "--address" option, but the "grails app-engine run" command doesn't. I hacked the scripts/AppEngine.groovy plugin and harcoded the address parameter into startDevServer().
There was some other stuff that I didn't take notes on, but (other than registration being turned off) Popstat is doing what it did before.

Overall, though, it wasn't a great experience. Google turns off random bits of Java (for security and ease of management), which means that very few third-party libraries are going to work. You'll probably have to do some porting of your own code as well. That, combined with the admin service being down all morning, left a bad taste. The free hosting thing is great for demo apps but I think I'll stick to something like Amazon EC2 for real work. I'm very curious to see how Microsoft Azure stacks up (it's much more of a direct competitor to App Engine than the roll-it-all-yourself EC2)

You should follow me on twitter here.


Anonymous Anonymous said...

Hi, I am also attempting a GAE + Grails experiment along the same lines as yours. I ran across the referenced fix you mention for the NamingException issue (i.e., installing a fake internalPersistenceAnnotationProcessor) but have had little luck with it. Did you simply add your bean definition to the existing resources.groovy file?

5:48 AM  
Blogger cks said...

I used conf/spring/resources.xml:


<bean id="org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
class="com.praxisbridge.popstat.GaeFixInternalPersistenceAnnotationProcessor" />


7:48 AM  
Blogger cks said...

Oh, and I sometimes (but not always) get this:


8:02 AM  
Anonymous Anonymous said...

Hmm.. I still get the NamingException. I have tried putting the bean declaration in resources.groovy, resources.xml and even directly into the WEB-INF/applicationContext.xml file. I must be hosing something somewhere....

11:55 AM  
Anonymous Anonymous said...

ignore my last post. I was deploying the wrong app profile. heh. FWIW, I could only get the bean declaration to work in resources.xml and not in resources.groovy.

I am now experiencing the double creation error. Onward and upward!

Thanks for your help. I will chime in with updates/progress

12:23 PM  
Blogger cks said...

Ok, updating to version 0.8.3 of the AppEngine plugin seems to have helped with the double creation error referenced earlier. I want to do a little more testing, then I'll update the blog post with an addendum...

4:56 PM  
Blogger Unknown said...

Yeah I also updated both the gorm-jpa plugin and the app-engine plugin the other day, but its something of a 'two steps forward, one step back' mode of progress.

I am still having great difficulties managing even the most basic of 1-N relationships, regardless of the persistence API I choose (I have gone back and forth between JPA and JDO). Everytime I think I am getting closer, I hit another roadblock. Not sure how much more stamina I have.

6:28 AM  
Anonymous secure tabs said...

This is incredible I got excellent things in here thongs I had never read, it has been really helpful for me thanks so much.

6:25 AM  

Post a Comment

<< Home