Created
May 16, 2012 16:40
-
-
Save sgodbillon/2712028 to your computer and use it in GitHub Desktop.
plugin example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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