Posts from November 2009

MongoDB plugin for Griffon

Posted

A couple of weeks ago, I showed how you could make MongoDB a bit more Groovy. In this post, I'll be covering a preview release of the Mongo DB plugin. Behind the scenes, this plugin uses Guice for Dependency Injection. 

Getting started:


Install the mongodb plugin:

griffon install-plugin mongo-db


In your conf directory create a file named MongoConfig.groovy listing the database connection details, like this:

mongo {
    host="localhost"
    port=27017
    dbName="mine"
    collectionName="testcoll"
}

Add the following bit to your Application.groovy file:

guice {
    modules = [ "MongoModule"]
}

MongoModule.groovy is provided by the plugin. Getting a collection Collections are the approximate equivalent to a RDBMS table. Collections will be wh2ere you do most of your work. We can get a reference to a collection by adding @Inject MongoDBCollectionFactory factory to our controller and calling injector.injectMembers(this). Guice uses the settings in MongoConfig to properly wire our Mongo and DB instance giving us a CollectionFactory. Let's make a collection called posts and populate a couple of documents:

def coll2 = factory.getCollection("posts")
coll2.insert(['title':'Whatever', 'postcreated':new Date(), 'comments':[
    'text':'A sample comment','datecreated':new Date(109,10,13)]] as BasicDBObject)
coll2.insert(['title':'Whatever1', 'postcreated':new Date()] as BasicDBObject)
coll2.insert(['title':'Whatever3', 'postcreated':new Date()] as BasicDBObject)

Dynamic Finders

Just before the factory returns the collection, it decorates it with code to generate GORM-like dynamic finders with operators like LessThan, LessThanEquals, GreaterThan, NotEqual, etc. Let's query our collection for all posts with a specific title:

def cursor3 = coll2.findByTitle('Whatever')

The return value is a DBCursor that we can iterate though. In addition to dynamic finders, the MongoDB plugin allows you to access child documents. This is extra useful because Mongo usually stores related documents as child documents of a parent. An underscore between two property names indicates a property on a sub-document. So if you wanted to find the comments created on a specific date. You'd use a query like this:

coll.findByComments_DateCreated(new Date('2009-10-10'))

This plugin, codenamed MonGorm, is a preview release so everything isn't fully baked. Comments/feedback welcome (emails/tweets better than comments on this post)

BarCampDC3

Posted

 

One of the cool things about BarCamp is that you tend to find out about startups and people before they are big. Though I usually prefer 2-day camps, I made an exception for this one as it gave me a reason to go to the Air & Space Museum for the first time since middle school. 
 
The day started with introductions and session proposals which was pretty cool so that no one felt like a total stranger. I proposed a postmortem on developing for Google Wave. Unfortunately some folks misunderstood my use of postmortem as a declaration that Google Wave was dead. I even had to correct a couple of folks who came up to me later and said "I agree that Wave is dead..." I guess it's hard to gauge that sort of thing when you live in GOOG's backyard. It never entered my mind that it could've been read that way. 
 
There were lots of smart people there, I just  wish I weren't so jet-lagged or I would have conversed more. The night before I jumped on a flight at 10:10P MV time and via Philly, I was in DC 8 hrs later. The transcon was only enough for a quick nap (4hrs) and I needed much coffee to make it through my session. It was a mix of general Google Wave/gadget vs. robot stuff and a bit about Ribbit. I was really glad to see a session on Groovy/Grails... in DC of all places, the epitome of button-down conservatism (well when it comes to software at least ;-) ) At about 3P, I hit my wall and had to crash. Unfortunately I wasn't back up in time to make it to the afterparty, maybe next time. 
 
My VirginMobile Broadband2Go card saved the day once again as the venue had flaky wifi. It was the basement of the MLK Library which had less coverage than the above ground floors. It was also the one spot in the city where all T-Mo phones had problems but AT&T worked like a dream.

 

RuPy 2009

Posted

Having caught back up on lost sleep, I'd say that RuPy is one of my favorite smaller conferences this year. It took place in Poznan, Poland on November 7-8th. As the name indicates, the first couple of incarnations of RuPy were focused on Ruby and Python. This year they expanded the field to dynamic languages in general. However, I was the ONLY non-Ruby/Python presenter there. I guess some folks got scared by the distance and or language. All sessions at RuPy were done in English. It did take a while to go to Poznan from California, but the warmth of the organizers made it worthwhile.
 
I presented Griffon: Swing just got fun again to a nearly full room and it went really well despite some hiccups in demos due to my having been sleep deprived. You see I had a dev event for work that I had attend so I flew from SFO on a British Airways red-eye to London at 7:50PM Thursday, then hopped on a LOT Polish Airlines flight to Warsaw and a prop plane to Poznan on Friday evening. I arrived in Poznan about 8 hrs before I was due to present. 
 
During the Q&A portion of my preso, I had to address the "Strachan incident." Sigh.
 
Charlie Nutter attended my session, we were in the same time slot at StrangeLoop, and was a good sport about the minor ribbing I gave him about Groovy's win at the ScriptBowl. His tweet about "implementing Griffon in 75 lines of code" caused a bit of a tempest in a teapot but it was a joke. So much for my saying that Groovy and JRuby's relationship has evolved and the two are comfortable with each other.
 
The organizers had to roll with the punches a little as some folks cancelled at the last minute, as in no-showed or got to Poznan but became incredibly ill. If you are ill or cancel with adequate notice, I understand, but we developers live and die by our word, integrity, and body of work. It doesn't matter that it is RuPy and not RubyConf. If you give your word, you should keep it. And we all should learn from Andy Azula that flying the morning of a speaking engagement is incredibly risky.
 
The Rubyists and Pythonistas(yes, they call themselves that) I met were really cool but I would have liked more Groovy people to have come out. There is a lot our communities can learn from each other and cooperate on. 
 
Video of the session will available in about 3 weeks or so I've been told.

MongoDB made more Groovy

Posted

The session after mine here at RuPy was MongoDB presented by Mike Dirlof(@mdirlof). I looked at the Java examples yet they left a bit to be desired as they had the usual Java verbosity problems. One of the cooler lesser known things about Groovy is that Groovy can coerce objects to a specific interface. We use this alot for one-off WindowListerners interfaces and such. That same concept can be applied to the classes as well. We can take code from the Java MongoDB tutorial to make it more Groovy.

import com.mongodb.*

def m = new Mongo()

def db = m.getDB("mydb")
def coll = db.getCollection("testCollection")

coll.drop()
 
def doc = [name:"MongoDB", type:"database", count:1,
            info: [x:203, y:102]
          ] as BasicDBObject
def doc2 = [name:"MongoDB2", type:"database", count:2,
    info: [x:203, y:102] ] as BasicDBObject

    
coll.insert(doc)
coll.insert(doc2)

println coll.getCount()

def obj = coll.findOne([count:1] as BasicDBObject)
println obj

println "showing a custom query"
def cur = coll.find([count:['$lt':3]] as BasicDBObject)
while(cur.hasNext()) {
    println cur.next()
}

Because MongoDB's BasicDBObject is a subclass of HashMap, we can produce concise code that looks closer to the Ruby, Python, and Javascript examples Matt has presented. We can also nest documents within documents, turtles all the way down. Only the othermost document needs to be cast, the rest get cast to documents automatically. It seems that MongoDB's special params begin with a dollar sign ($gt, $lt, etc) need to be passed as a String literal with apostrophes.

Griffon Guice Plugin

Posted

Having come back from StrangeLoop last week and talking to some our users, I've been thinking a lot potential blockers that might be preventing people from using Griffon in their work applications. One is those is probably dependency injection. Why I chose Guice - I detest XML. I like Guice's modules as a non-XML tag soup way to specify classes to be bound. - Guice's footprint is several magnitudes smaller than Spring. The smallest Guice application requires only 600KB of jar dependencies whereas a comparable Spring application would require several megabytes. Our users are already taking a hit for having to get the groovy-all.jar over the wire. I don't want to add to that pain.

Getting Started

Given an app with the Guice plugin installed(griffon install-plugin guice), let's start by creating a couple classes in our src/ directory. Below is a Notifier interface and an implementation:

Notifier.groovy

public interface Notifier {
	public void sendMessage(String message);
}

Mail.groovy

public class Mail implements Notifier {
	public void sendMessage(String message) {
		println "Sending ${message} by Mail"
	}
}

As mentioned before, Guice uses Modules instead of XML to specify binding. We can bind our Notifier to the implementation Mail very easily:

GuiceAppModule.groovy

import com.google.inject.*

public class GuiceAppModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Notifier.class).to(Mail.class);
    }
}

Wiring in the Griffon bits

Our plugin does most of the heavy lifting resolving the names of our modules and injecting a Guice injector into the required classes. We just need to give it a few configuration details in griffon-app/conf/Application.groovy. We need to tell Guice where to inject and what modules to inject:

guice {
	injectInto = ["controller"]
	modules = ["GuiceAppModule"]
}

The last piece is injecting and using our member fields from our controller. In the controller or wherever you deem appropriate, the following will inject the members:

GuiceDemoController.groovy

import com.google.inject.*

class GuiceDemoController {
    // these will be injected by Griffon
    def model
    def view
	@Inject Notifier notifier

    void mvcGroupInit(Map args) {
        // this method is called after model and view are injected
		injector.injectMembers(this)
		notifier.sendMessage("test");
    }
}

When run, the app will print "Sending test by Mail" to the console. The maintainers of Guice caution somewhat against member injection as being less testable. A more traditional constructor-based injection would force Guice to reach below the plugin layer. It's still early days, it might find its way down there anyways.