Skip to content

Instantly share code, notes, and snippets.

@sgodbillon
Created May 16, 2012 16:40
Show Gist options
  • Save sgodbillon/2712028 to your computer and use it in GitHub Desktop.
Save sgodbillon/2712028 to your computer and use it in GitHub Desktop.
plugin example
package play.modules.mongodb
import com.mongodb.casbah.MongoConnection
import com.mongodb.casbah.MongoCollection
import com.mongodb.casbah.MongoDB
import play.api._
class MongoPlugin(app :Application) extends Plugin {
lazy val helper :MongoHelper = {
val parsedConf = MongoPlugin.parseConf(app)
try {
MongoHelper(parsedConf._1, parsedConf._2, parsedConf._3, parsedConf._4)
} catch {
case e => throw PlayException("MongoPlugin Initialization Error", "An exception occurred while initializing the MongoPlugin.", Some(e))
}
}
/** Returns the current [[com.mongodb.casbah.MongoConnection]]. */
def connection :MongoConnection = helper.connection
/** Returns the current [[com.mongodb.casbah.MongoDB]]. */
def db :MongoDB = helper.db
/** Returns the named collection from current db. */
def collection(name :String) :MongoCollection = try {
helper.db(name)
} catch {
case uhe :java.net.UnknownHostException => throw app.configuration.globalError("MongoPlugin error: The server host '%s' is unknown, please check your conf/application.conf or your network configuration.".format(uhe.getMessage), Some(uhe))
case e => throw e
}
override def onStart {
Logger info "MongoPlugin starting..."
Logger.info("MongoPlugin successfully started with db '%s'! Servers:\n\t\t%s".format(helper.dbName, helper.servers.map { s =>
"[%s -> %s:%s]".format(s.name, s.host, s.port)
}.mkString("\n\t\t")))
(helper.username, helper.password) match {
case (Some(u),Some(p)) => {
val auth = db.authenticate(u,p)
if (auth==false) throw app.configuration.globalError("MongoPlugin error: Authentication failed with username/password")
else Logger.info("MongoPlugin : authentication of user "+u+ " successful")
}
case _ => Logger.info("No authentication")
}
}
}
/**
* MongoDB access methods.
*/
object MongoPlugin {
/** Returns the current [[com.mongodb.casbah.MongoConnection]] connection. */
def connection(implicit app :Application) :MongoConnection = current.connection
/** Returns the current [[com.mongodb.casbah.MongoDB]]. */
def db(implicit app :Application) :MongoDB = current.db
/** Returns the named collection from current db. */
def collection(name :String)(implicit app :Application) :MongoCollection = current.collection(name)
/** Returns the current instance of the plugin. */
def current(implicit app :Application) :MongoPlugin = app.plugin[MongoPlugin] match {
case Some(plugin) => plugin
case _ => throw PlayException("MongoPlugin Error", "The MongoPlugin has not been initialized! Please edit your conf/play.plugins file and add the following line: '400:play.modules.mongodb.MongoPlugin' (400 is an arbitrary priority and may be changed to match your needs).")
}
/** Returns the current instance of the plugin (from a [[play.Application]] - Scala's [[play.api.Application]] equivalent for Java). */
def current(app :play.Application) :MongoPlugin = app.plugin(classOf[MongoPlugin]) match {
case plugin if plugin != null => plugin
case _ => throw PlayException("MongoPlugin Error", "The MongoPlugin has not been initialized! Please edit your conf/play.plugins file and add the following line: '400:play.modules.mongodb.MongoPlugin' (400 is an arbitrary priority and may be changed to match your needs).")
}
private[mongodb] val DEFAULT_HOST = "localhost"
private[mongodb] val DEFAULT_PORT = 27017
private def parseConf(app :Application) = {
(app.configuration.getString("mongodb.db") match {
case Some(db) => db
case _ => throw app.configuration.globalError("Missing configuration key 'mongodb.db'!")
}, app.configuration.getConfig("mongodb.servers") match {
case Some(config) => {
config.keys.toList.sorted.map(_.span(_ != '.')._1).toSet.map { name :String =>
Server(
name,
config.getString(name + ".host").getOrElse(MongoPlugin.DEFAULT_HOST),
config.getInt(name + ".port").getOrElse(MongoPlugin.DEFAULT_PORT)
)
}
}
case _ => Set(
Server("_default_", app.configuration.getString("mongodb.host").getOrElse(MongoPlugin.DEFAULT_HOST), app.configuration.getInt("mongodb.port").getOrElse(MongoPlugin.DEFAULT_PORT))
)
}, app.configuration.getString("mongodb.username"), app.configuration.getString("mongodb.password")
)
}
}
/**
* Play Json lib <=> DBObject converter methods (includes implicits).
*/
object MongoJson {
import play.api.libs.json._
import org.bson.BSONObject
import org.bson.types.ObjectId
import com.mongodb.BasicDBObject
import com.mongodb.BasicDBList
import com.mongodb.DBObject
import java.util.Date
import scala.collection.JavaConversions
/** Serializes the given [[com.mongodb.DBObject]] into a [[play.api.libs.json.JsValue]]. */
def toJson(dbObject: DBObject) :JsValue = Json.toJson(dbObject)(BSONObjectFormat)
/** Deserializes the given [[play.api.libs.json.JsValue]] into a [[com.mongodb.DBObject]]. */
def fromJson(v: JsValue) :DBObject = Json.fromJson[DBObject](v)(BSONObjectFormat)
/** Formatter for [[com.mongodb.DBObject]], handling serialization/deserialisation for DBObjects. */
implicit object BSONObjectFormat extends Format[DBObject] {
def reads(json: JsValue) :DBObject = parse(json.asInstanceOf[JsObject])
def writes(bson: DBObject) :JsValue = Json.parse(bson.toString)
private def parse(map: JsObject) :BasicDBObject = new BasicDBObject(
JavaConversions.mapAsJavaMap(Map() ++ map.fields.map { p =>
(p._1, p._2 match {
case v: JsObject => {
specialMongoJson(v).fold (
normal => parse(normal),
special => special
)
}
case v: JsArray => { parse(v) }
case v: JsValue => { parse(v) }
})
})
)
private def specialMongoJson(json: JsObject) :Either[JsObject, Object] = {
if(json.fields.length > 0) {
json.fields(0) match {
case (k, v :JsString) if k == "$date" => Right(new Date(v.value.toLong))
case (k, v :JsString) if k == "$oid" => Right(new ObjectId( v.value ))
case (k, _) if k.startsWith("$") => throw new RuntimeException("unsupported specialMongoJson " + k)
case _ => Left(json)
}
} else Left(json)
}
private def parse(array: JsArray) :BasicDBList = {
val r = new BasicDBList()
r.addAll(scala.collection.JavaConversions.seqAsJavaList(array.value map { v =>
parse(v).asInstanceOf[Object]
}))
r
}
private def parse(v: JsValue) :Any = v match {
case v: JsObject => parse(v)
case v: JsArray => parse(v)
case v: JsString => v.value
case v: JsNumber => v.value
case v: JsBoolean => v.value
case JsNull => null
case v: JsUndefined => null
}
}
implicit object ObjectIdFormat extends Format[ObjectId] {
def reads(json: JsValue) :ObjectId = {
json match {
case obj: JsObject if obj.keys.contains("$oid") => new ObjectId( (obj \ "$oid").toString )
case s: JsString => new ObjectId(s.value)
case _ => throw new RuntimeException("unsupported ObjectId " + json)
}
}
def writes(objectId: ObjectId) :JsObject = {
JsObject(Seq("$oid" -> JsString(objectId.toString)))
}
}
implicit object MongoDateFormat extends Format[Date] {
def reads(json: JsValue) :Date = json match {
case obj: JsObject if obj.keys.contains("$date") => new Date((obj \ "$date").toString.toLong)
case _ => throw new RuntimeException("unsupported Date " + json)
}
def writes(date: Date) :JsObject = JsObject( Seq("$date" -> JsString(date.getTime + "")) )
}
}
private[mongodb] case class MongoHelper(dbName :String, servers: Set[Server], username:Option[String] = None, password:Option[String]= None) {
import com.mongodb.ServerAddress
lazy val connection :MongoConnection = {
if(servers.size > 1)
MongoConnection(servers.map { server =>
new ServerAddress(server.host, server.port)
}.toList)
else MongoConnection(servers.head.host, servers.head.port)
}
def db :MongoDB = connection(dbName)
def collection(name :String) :MongoCollection = db(name)
}
private[mongodb] case class Server(
name: String,
host :String = MongoPlugin.DEFAULT_HOST,
port :Int = MongoPlugin.DEFAULT_PORT
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment