Golo, Java, Maven … and MongoDb

The last time (“Golo, Think different”), i tried to quickly introduce “Golo”, and i explained that Golo was playing very well with Java. You can even generate a Maven project, add java source code and frameworks dependencies!

Create Golo Maven Project

Try this command:

golo new --type maven contacts

It creates a directory contacts:

contacts/
├── src/
|   └── main/      
|       └── golo/
|           └── main.golo
└── pom.xml

You can open main.golo:

module contacts

function main = |args| {
  println("Hello contacts!")
}

Now, open pom.xml and search <plugin> node about exec-maven-plugin:

  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.1</version>
    <executions>
      <execution><goals><goal>java</goal></goals></execution>
    </executions>
    <configuration>
      <mainClass>contacts</mainClass>
    </configuration>
  </plugin>

You can see that contacts is considered as the main class, like the module name of main.golo with a main method.

Compile your new Golo project

search <plugin> node about maven-assembly-plugin, and add <outputDirectory>./</outputDirectory> in the <configuration> node:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.4</version>
    <configuration>
      <archive>
        <manifest>
          <mainClass>contacts</mainClass>
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <outputDirectory>./</outputDirectory>

    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

Remark: it’s just handier to do that, i agree it’s not probably a very good practice

And now, run the command mvn and you’ll get a new jar file: contacts-0.0.1-SNAPSHOT-jar-with-dependencies.jar that you can run like that:

java -jar contacts-0.0.1-SNAPSHOT-jar-with-dependencies.jar  

Add some java code

In the main directory, create a java directory, and a package inside, ie org.k33g.tools with a java class Hello.java:

package org.k33g.tools;

public class HelloWorld {
  public void en() {
    System.out.println("Hello World!");
  }
  public void fr() {
    System.out.println("Salut à Tous!");
  }
}

This is your project:

contacts/
├── src/
|   └── main/      
|       └── golo/
|       |   └── main.golo
|       └── java/
|           └── org/
|               └── k33g/    
|                   └── tools/ 
|                       └── HelloWorld.java       
└── pom.xml

Modifiy your main.golo file

module contacts

import org.k33g.tools.HelloWorld

function main = |args| {
  let hello = HelloWorld()
  
  hello: en()
  hello: fr()
}

Build your project: mvn and run it: java -jar contacts-0.0.1-SNAPSHOT-jar-with-dependencies.jar , you’ll get this:

Hello World!
Salut à Tous!

Use an “external” java framework

MongoDB

I love to use MongoDB and it would be fine to “play with it in Golo” ;) then add this dependency inside the <dependencies> node:

<dependency>
  <groupId>org.mongodb</groupId>
  <artifactId>mongo-java-driver</artifactId>
  <version>2.11.4</version>
  <type>jar</type>
  <scope>compile</scope>
</dependency>

In golo directory, create a mongo.golo file and copy this content:

module mongo

import com.mongodb.MongoClient
import com.mongodb.MongoException
import com.mongodb.WriteConcern
import com.mongodb.DB
import com.mongodb.DBCollection
import com.mongodb.BasicDBObject
import com.mongodb.DBObject
import com.mongodb.DBCursor
import com.mongodb.ServerAddress
import org.bson.types.ObjectId

struct mongo = {
  _mongoClient,
  _db
}

augment mongo {
  function initialize = |self, databaseName, host, port| {
    self: _mongoClient(MongoClient(host, port))
    self: _db(self: _mongoClient(): getDB(databaseName))
    return self
  }

  function db = |self| -> self: _db()
  function collection = |self, collectionName| {
    let dbCollection = self: _db(): getCollection(collectionName)
    let newCollection = mongoCollection(
      dbCollection,
      null, null, null
    )
    return newCollection
  }

  function model = |self, collectionName| {
    let dbCollection = self: _db(): getCollection(collectionName)
    let newModel = mongoModel(dbCollection, BasicDBObject())
    return newModel
  }
}

struct mongoCollection = {
  _collection,
  skip,
  limit,
  sort
}

augment mongoCollection {
  function options = |self, cursor| {
    if self: sort() isnt null {
      cursor: sort(BasicDBObject(self: sort(): get(0), self: sort(): get(1)))
      self: sort(null)
    }
    if self: skip() isnt null {
      cursor: skip(self: skip()): limit(self: limit())
      self: skip(null): limit(null)
    }
    return cursor
  }
  #  helpers :
  function cursorToListOfMaps = |self, cursor| { #  return list of HashMaps
    let models = list[]
    cursor: each(|doc| {
      let map = doc: toMap()
      let id = doc: getObjectId("_id"): toString()
      map: put("_id", id)
      models: add(map)
    })
    return models
  }
  #  helpers :
  function cursorToList = |self, cursor| { #  return list of MongoModels
    let models = list[]
    cursor: each(|doc| {
      let newModel = mongoModel(self: _collection(), BasicDBObject())
      newModel: fromMap(doc: toMap())
      models: add(newModel)
    })
    return models
  }

  function fetch = |self| {
    let cursor = self: _collection(): find()
    self: options(cursor)
    return self: cursorToList(cursor)
  }
  function fetchMaps = |self| {
    let cursor = self: _collection(): find()
    self: options(cursor)
    return self: cursorToListOfMaps(cursor)
  }
  function find = |self, fieldName, value| {
    let query = BasicDBObject(fieldName, value)
    let cursor = self: _collection(): find(query)
    self: options(cursor)
    return self: cursorToList(cursor)
  }
  function findMaps = |self, fieldName, value| {
    let query = BasicDBObject(fieldName, value)
    let cursor = self: _collection(): find(query)
    self: options(cursor)
    return self: cursorToListOfMaps(cursor)
  }
  function like = |self, fieldName, value| {
    let query = BasicDBObject(fieldName, java.util.regex.Pattern.compile(value))
    let cursor = self: _collection(): find(query)
    self: options(cursor)
    return self: cursorToList(cursor)
  }
  function likeMaps = |self, fieldName, value| {
    let query = BasicDBObject(fieldName, java.util.regex.Pattern.compile(value))
    let cursor = self: _collection(): find(query)
    self: options(cursor)
    return self: cursorToListOfMaps(cursor)
  }
  function query = |self, query| {
    let cursor = self: _collection(): find(query)
    self: options(cursor)
    return self: cursorToList(cursor)
  }
  function queryMaps = |self, query| {
    let cursor = self: _collection(): find(query)
    self: options(cursor)
    return self: cursorToListOfMaps(cursor)
  }
}

struct mongoModel = {
  _collection,
  _basicDBObject
}

augment mongoModel {
  function id = |self| -> self: _basicDBObject(): getObjectId("_id"): toString()

  function field = |self, fieldName, fieldValue| {
    self: _basicDBObject(): put(fieldName, fieldValue)
    return self
  }
  function field = |self, fieldName| -> self: _basicDBObject(): get(fieldName)

  function insert = |self| {
    self: _collection(): insert(self: _basicDBObject())
    return self
  }

  function update = |self| {
    let id = self: _basicDBObject(): get("_id")
    self: _basicDBObject(): removeField("_id")
    let searchQuery = BasicDBObject(): append("_id", ObjectId(id))
    self: _collection(): update(searchQuery, self: _basicDBObject())
    self: _basicDBObject(): put("_id", ObjectId(id))
    return self
  }

  function fetch = |self, id| {
    let searchQuery = BasicDBObject(): append("_id", ObjectId(id))
    self: _collection(): find(searchQuery): each(|doc| {
      self: _basicDBObject(): putAll(doc)
    })
    return self
  }
  function fetch = |self| {
    return self: fetch(self: id())
  }
  function remove = |self, id| {
    let searchQuery = BasicDBObject(): append("_id", ObjectId(id))
    let doc = self: _collection(): find(searchQuery): next()
    self: _basicDBObject(): putAll(doc)
    self: _collection(): remove(doc)
    return self
  }
  function remove = |self| {
    return self: remove(self: id())
  }
  function toMap = |self| {
    let map = self: _basicDBObject(): toMap()
    map: put("_id", self: id())
    return map
  }
  function fromMap = |self, fieldsMap| {
    self: _basicDBObject(BasicDBObject(fieldsMap))
    return self
  }
  function toJsonString = |self| -> JSON.stringify(self: toMap())

  function fromJsonString = |self, jsonString| {
    let bo = BasicDBObject()
    bo: putAll(JSON.parse(jsonString))
    self: _basicDBObject(bo)
    return self
  }
}

Modify main.golo to play with MongoDB

Change the content of main.golo by this:

module contacts

import mongo

function main = |args| {

  let mongocli = mongo(): initialize("ducksdb", "localhost", 27017)

  let riri = mongocli: model("ducks")
    : field("firstName", "Riri")
    : field("lastName", "Duck")
    : insert()

  let fifi = mongocli: model("ducks")
    : field("firstName", "Fifi")
    : field("lastName", "Duck")
    : insert()

  let loulou = mongocli: model("ducks")
    : field("firstName", "Loulou")
    : field("lastName", "Duck")
    : insert()

  let ducks = mongocli: collection("ducks")

  ducks: fetch(): each(|duck| {
    println(duck: toJsonString())
  })

  ducks: fetchMaps(): each(|duck| {
    println(duck)
  })

  ducks: like("firstName", ".*i.*"): each(|duck| {
    println(duck: toJsonString())
  })

}

Now, build your project: mvn, launch MongoDb server (mongod) and run your jar: java -jar contacts-0.0.1-SNAPSHOT-jar-with-dependencies.jar , you’ll get something like this:

{"firstName":"Riri","lastName":"Duck","_id":"53a9514b30043a04aa8f1cb5"}
{"firstName":"Fifi","lastName":"Duck","_id":"53a9514b30043a04aa8f1cb6"}
{"firstName":"Loulou","lastName":"Duck","_id":"53a9514b30043a04aa8f1cb7"}
{_id=53a9514b30043a04aa8f1cb5, firstName=Riri, lastName=Duck}
{_id=53a9514b30043a04aa8f1cb6, firstName=Fifi, lastName=Duck}
{_id=53a9514b30043a04aa8f1cb7, firstName=Loulou, lastName=Duck}
{"firstName":"Riri","lastName":"Duck","_id":"53a9514b30043a04aa8f1cb5"}
{"firstName":"Fifi","lastName":"Duck","_id":"53a9514b30043a04aa8f1cb6"}

So you can see it’s very easy to create hybrid projects (Golo+Java+Mongo+ … and so on).

Have fun with Golo!

blog comments powered by Disqus

Related posts