GMongo available at Maven Central

July 3, 2010

A maintenance release (0.5.1) of GMongo was launched. It just fixed a bug with com.mongodb.DB#createCollection.

But the good news is the GMongo availability in the Maven Central (http://repo2.maven.org/maven2/).

Maven:

<dependency>
      <groupId>com.gmongo</groupId>
      <artifactId>gmongo</artifactId>
      <version>0.5.1</version>
</dependency>

Ivy:

<dependency org="com.gmongo" name="gmongo" rev="0.5.1"/>

Groovy Grape:

@Grab(group='com.gmongo', module='gmongo', version='0.5.1')

This should compile and run seamlessly in an environment with Groovy 1.7.2 (or later):

@Grab("com.gmongo:gmongo:0.5.1")
import com.gmongo.GMongo

def mongo = new GMongo("127.0.0.1", 27017)
def db = mongo.getDB('myDb')

db.greetings.insert(hello: 'world')

GMongo 0.5 Released

June 20, 2010

GMongo is an alternative to de default Java driver for Mongodb. It’s use an easy and less verbose syntax, the grammar is very close to the official mongo shell cliente (javascript).

It’s just a wrapper around the Java driver. So, every single method of the the official driver is available here too.

The main class is the com.gmongo.GMongo. It has the same API of the com.mongodb.Mongo but it’s not a subclass. Instead, the methods calls are delegated. Despite GMongo, all other classes are the same from the Java driver.

To be more practical, here are some examples:

// To download GMongo on the fly and put it at classpath
@Grab(group='com.gmongo', module='gmongo', version='0.5.1')
import com.gmongo.GMongo
// Instantiate a com.gmongo.GMongo object instead of com.mongodb.Mongo
// The same constructors and methods are available here
def mongo = new GMongo("127.0.0.1", 27017)

// Get a db reference in the old fashion way
def db = mongo.getDB("gmongo")

// Collections can be accessed as a db property (like the javascript API)
assert db.myCollection instanceof com.mongodb.DBCollection
// They also can be accessed with array notation
assert db['my.collection'] instanceof com.mongodb.DBCollection

// Insert a document
db.languages.insert([name: 'Groovy'])
// A less verbose way to do it
db.languages.insert(name: 'Ruby')
// Yet another way
db.languages << [name: 'Python']

// Insert a list of documents
db.languages << [[name: 'Javascript', type: 'prototyped'], [name: 'Ioke', type: 'prototyped']]

def statics = ['Java', 'C', 'VB']

statics.each {
	db.languages << [name: it, type: 'static']
}

// Finding the first document
def lang = db.languages.findOne()
assert lang.name == 'Groovy'
// Set a new property
lang.site = 'http://groovy.codehaus.org/'
// Save the new version
db.languages.save lang

assert db.languages.findOne(name: 'Groovy').site == 'http://groovy.codehaus.org/'

// Counting the number of documents in the collection
assert db.languages.find(type: 'static').count() == 3

// Another way to count
assert db.languages.count(type: 'prototyped') == 2

// Updating a document using the '$set' operator
db.languages.update([name: 'Python'], [$set: [paradigms: ['object-oriented', 'functional', 'imperative']]])

assert 3 == db.languages.findOne(name: 'Python').paradigms.size()

// Using upsert
db.languages.update([name: 'Haskel'], [$set: [paradigms: ['functional']]], true)

assert db.languages.findOne(name: 'Haskel')

// Removing some documents
db.languages.remove(type: 'prototyped')
assert 0 == db.languages.count(type: 'prototyped')

// Removing all documents
db.languages.remove([:])
assert 0 == db.languages.count()

// To ensure complete consistency in a session use DB#inRequest
// It is analogous to user DB#requestStarted and DB#requestDone
db.inRequest {
	db.languages.insert(name: 'Objective-C')
	assert 1 == db.languages.count(name: 'Objective-C')
}

And a simple MapReduce:

@Grab(group='com.gmongo', module='gmongo', version='0.5.1')
import com.gmongo.GMongo

// There is some bug using the [Random] word into codesnipt plugin
import java.util.Random as Rand

def mongo = new GMongo("127.0.0.1", 27017)
def db = mongo.getDB("gmongo")

def words = ['foo', 'bar', 'baz']
def rand  = new Rand()		

1000.times {
	db.words << [word: words[rand.nextInt(3)]]
}

assert db.words.count() == 1000

def result = db.words.mapReduce(
	"""
	function map() {
		emit(this.word, {count: 1})
	}
	""",
	"""
	function reduce(key, values) {
		var count = 0
		for (var i = 0; i < values.length; i++)
			count += values[i].count
		return {count: count}
	}
	""",
	"mrresult",
	[:] // No Query
)

assert db.mrresult.count() == 3
assert db.mrresult.find()*.value*.count.sum() == 1000

It’s a stable version and still a work in progress. The only dependency is the mongo Java driver version 2.0 and, of course, Groovy. It’s tested under Groovy 1.7.2 and 1.7.3. It’s opensource and hosted at http://github.com/poiati/gmongo.

The binaries can be found at Maven Central.
Click here for more details.

Any bug, suggestion or issue, please, contact me.

Forwarding Objective-C Messages

December 5, 2009

Unlike Java or plain C, Objective-C work with messages. You don’t invoke a method on an object, instead, you send a message to it (like the Ruby language). This approach let a more dynamic behavior. For instance, suppose that you have this class:

// SomeClass
#import <Cocoa/Cocoa.h>
@interface SomeClass : NSObject {
}
-(void)doSomething
@end
#import "SomeClass.h"
#import "Delegate.h"
@implementation SomeClass
-(void)doSomething {
   NSLog(@"doSomething was called on %@", [self className]);
}
@end

As you can see it has only one instance method definition, called “doSomething”. Thus, it can respond to the “doSomething” message. But, what happens when we send a message that the receiver can’t respond to ? Lets make a try:

The receiver is the object that will receive the message. For example, in the following statement:

Dog *dog = [Dog new];
[dog bark];

dog is the receiver and bark is the message.

Here is our main code:

//MethodMissing
#import <Foundation/Foundation.h>
#import "SomeClass.h"
int main (int argc, const char * argv[]) {
  NSAutoreleasePool *pool = [NSAutoreleasePool new];
  SomeClass *someClass = [SomeClass new];
  [someClass doSomething];
  [someClass doSomethingElse];
  [pool drain];
  return 0;
}

This code compiles with warnings, because the message “doSomethingElse” is not defined in the SomeClass interface. Errors in the Objective-C message dispatch system occurs at runtime. Programmers need to be more careful when dealing with more dynamic languages.

Running the code we got the following result:


MethodMissing[1695:a0f] doSomething was called on SomeClass
MethodMissing[1695:a0f] -[SomeClass doSomethingElse]: unrecognized selector sent to instance 0x10010c6c0
MethodMissing[1695:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SomeClass doSomethingElse]: unrecognized selector sent to instance 0x10010c6c0'

Not surprisingly the program crashed. First it invoke our declared “doSomething” message and logged the message to the console, all ok until now. But, in line eight we got a NSInvalidArgumentException with the error “-[SomeClass doSomethingElse]: unrecognized selector sent to instance 0x10010c6c0″.

This error message is very readable, the problem is that, there isn’t any message that respond to “doSomethingElse” in the class “SomeClass”, even at runtime.

And we got to the key topic of this post. We can handle unrecognized selectors messages and do a special treatment when it arrive to the receiver. How we do that ?

We need to overwrite two methods from the NSObject class in the receiver class:
-(void)forwardInvocation:(NSInvocation *)invocation
-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector

An NSInvocation is an Objective-C message rendered static, that is, it is an action turned into an object. NSInvocation objects are used to store and forward messages between objects and between applications.

Now our classes looks like this:

// ForwardClass
#import <Cocoa/Cocoa.h>
@interface ForwardClass : NSObject {
}
-(void)doSomethingElse;
@end
#import "ForwardClass.h"
@implementation ForwardClass
-(void)doSomethingElse {
	NSLog(@"doSomething was called on %@", [self className]);
}
@end
// SomeClass
#import <Cocoa/Cocoa.h>
@interface SomeClass : NSObject {
	id forwardClass;
}
-(void)doSomething;
@end
#import "SomeClass.h"
#import "ForwardClass.h"
@implementation SomeClass
-(id)init {
	if (self = [super init]) {
		forwardClass = [ForwardClass new];
	}
	return self;
}
-(void)doSomething {
	NSLog(@"doSomething was called on %@", [self className]);
}
-(void)forwardInvocation:(NSInvocation *)invocation {
	if (! forwardClass) {
		[self doesNotRecognizeSelector: [invocation selector]];
	}
	[invocation invokeWithTarget: forwardClass];
}
-(NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
	NSMethodSignature *signature = [super methodSignatureForSelector:selector];
	if (! signature) {
		signature = [forwardClass methodSignatureForSelector:selector];
	}
	return signature;
}
@end

When an object receive a message it doesn’t recognize, it wraps the invocation in a NSInvocation object and call the -(void)forwardInvocation passing it as parameter. But, first, it call the -(NSMethodSignature*)methodSignatureForSelector to get the method signature for the given selector.

Now, running the same program again we got:


MethodMissing[523:a0f] doSomething was called on SomeClass
MethodMissing[523:a0f] doSomethingElse was called on ForwardClass

And the program finished without any problems.

There are a lot of uses for this technic, some examples are:

  • Wrap one object in a logger object that intercepts and records the invocation of interesting
    messages.

  • Implement “synthetic” messages that are handled by other methods in your class. Imagine creating a generic database record object that catches any property message it receives (i.e., -saleDate, -setSaleDate:) and automatically translates it into a record query. Instead of coding date = [record getDateFieldWithKey:@"SaleDate"], you could simply write date = [record saleDate], without ever writing a -saleDate method. NSManagedObject and CALayer are examples of classes that implement synthetic properties.
  • Create an object that forwards the message to a hierarchy of other objects, like a responder chain. Chapter 20 talks about responder chains. The proxy object would search a collection of other objects looking for one that implements the message

In a future post I will demonstrate one real world application of this.

 
Powered by Wordpress and MySQL. Theme by Shlomi Noach, openark.org