Skip to content
This repository has been archived by the owner on Jan 27, 2019. It is now read-only.

MongoURI support #8

Merged
merged 1 commit into from May 22, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 64 additions & 19 deletions src/main/scala/se/radley/plugin/salat/SalatPlugin.scala
Expand Up @@ -3,7 +3,7 @@ package se.radley.plugin.salat
import play.api._ import play.api._
import play.api.mvc._ import play.api.mvc._
import play.api.Play.current import play.api.Play.current
import com.mongodb.casbah.{WriteConcern, MongoCollection, MongoConnection} import com.mongodb.casbah.{WriteConcern, MongoCollection, MongoConnection, MongoURI}
import com.mongodb.ServerAddress import com.mongodb.ServerAddress


class SalatPlugin(app: Application) extends Plugin { class SalatPlugin(app: Application) extends Plugin {
Expand Down Expand Up @@ -39,34 +39,79 @@ class SalatPlugin(app: Application) extends Plugin {
"/" + db "/" + db
} }
} }

/**
* Extracts host as String and port as Int from host string
* and defaults port to 27017 if it doesn't exist.
*
* E.g. localhost:9999 returns (localhost, 9999)
* E.g. localhost returns (localhost, 27017)
*/
def hostAndPort(host: String): (String, Int) = host.contains(':') match {
case true => {
val Array(h,p) = host.split(':')
(h,p.toInt)
}
case false => (host, 27017)
}


lazy val sources: Map[String, MongoSource] = configuration.subKeys.map { sourceKey => lazy val sources: Map[String, MongoSource] = configuration.subKeys.map { sourceKey =>
val source = configuration.getConfig(sourceKey).getOrElse(Configuration.empty) val source = configuration.getConfig(sourceKey).getOrElse(Configuration.empty)
val db = source.getString("db").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".db", "db missing for source[" + sourceKey + "]"))

// support MongoURI as per http://www.mongodb.org/display/DOCS/Connections
// Simple config val (host, port, user, password, hosts, db) = source.getString("uri").map{ uri => {
val host = source.getString("host").getOrElse("127.0.0.1") val all = MongoURI(uri)
val port = source.getInt("port").getOrElse(27017) val (host,port) = hostAndPort(all.hosts(0))
val user:Option[String] = source.getString("user") val user = all.username match {
val password:Option[String] = source.getString("password") case "null" => None

case null => None
// Replica set config case s => Some(s)
val hosts: List[ServerAddress] = source.getConfig("replicaset").map { replicaset => }
replicaset.subKeys.map { hostKey =>
val c = replicaset.getConfig(hostKey).get val password = all.password match {
val host = c.getString("host").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".replicaset", "host missing for replicaset in source[" + sourceKey + "]")) case null => None
val port = c.getInt("port").getOrElse(27017) case s => all.password.foldLeft("")(_ + _.toString) match {
new ServerAddress(host, port) case "" => None
}.toList case s => Some(s)
}.getOrElse(List.empty) }
}

// to List[ServerAddress]
val hosts = all.hosts.map(host => {
val (h,p) = hostAndPort(host)
new ServerAddress(h, p)
})

(host, port, user, password, hosts.toList, all.database)
}}.getOrElse{
val db = source.getString("db").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".db", "db missing for source[" + sourceKey + "]"))

// Simple config
val host = source.getString("host").getOrElse("127.0.0.1")
val port = source.getInt("port").getOrElse(27017)
val user:Option[String] = source.getString("user")
val password:Option[String] = source.getString("password")

// Replica set config
val hosts: List[ServerAddress] = source.getConfig("replicaset").map { replicaset =>
replicaset.subKeys.map { hostKey =>
val c = replicaset.getConfig(hostKey).get
val host = c.getString("host").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".replicaset", "host missing for replicaset in source[" + sourceKey + "]"))
val port = c.getInt("port").getOrElse(27017)
new ServerAddress(host, port)
}.toList
}.getOrElse(List.empty)

(host, port, user, password, hosts, db)
}


val writeConcern = WriteConcern.valueOf(source.getString("writeconcern", Some(Set("fsyncsafe", "replicassafe", "safe", "normal"))).getOrElse("safe")) val writeConcern = WriteConcern.valueOf(source.getString("writeconcern", Some(Set("fsyncsafe", "replicassafe", "safe", "normal"))).getOrElse("safe"))


// If there are replicasets configured go with those otherwise fallback to simple config // If there are replicasets configured go with those otherwise fallback to simple config
if (hosts.isEmpty) if (hosts.isEmpty)
sourceKey -> MongoSource(List(new ServerAddress(host, port)), db, writeConcern, user, password) sourceKey -> MongoSource(List(new ServerAddress(host, port)), db, writeConcern, user, password)
else else
sourceKey -> MongoSource(hosts, db, writeConcern) sourceKey -> MongoSource(hosts, db, writeConcern, user, password)
}.toMap }.toMap


override def enabled = !configuration.subKeys.isEmpty override def enabled = !configuration.subKeys.isEmpty
Expand Down
103 changes: 103 additions & 0 deletions src/test/scala/se/radley/plugin/salat/SalatSpec.scala
Expand Up @@ -29,6 +29,27 @@ object SalatSpec extends Specification {
("mongodb.default.replicaset.host2.host" -> "10.0.0.2") ("mongodb.default.replicaset.host2.host" -> "10.0.0.2")
) )
) )

lazy val fakeAppFromURI = FakeApplication(
additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"),
additionalConfiguration = Map(
("mongodb.default.uri" -> "mongodb://127.0.0.1:27017/salat-test")
)
)

lazy val fakeAppFromURIs = FakeApplication(
additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"),
additionalConfiguration = Map(
("mongodb.default.uri" -> "mongodb://127.0.0.1:27017,mongodb.org:1337/salat-test")
)
)

lazy val fakeAppFromURIsWithAuth = FakeApplication(
additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"),
additionalConfiguration = Map(
("mongodb.default.uri" -> "mongodb://nyancat:ILoveMyKittens@127.0.0.1:27017,mongodb.org:1337,192.168.88.99:27000/salat-test")
)
)


def salat = fakeApp.plugin[SalatPlugin].get def salat = fakeApp.plugin[SalatPlugin].get


Expand Down Expand Up @@ -76,5 +97,87 @@ object SalatSpec extends Specification {
salat.collection("salat-collection", "sourcethatdoesntexist") must throwAn[PlayException] salat.collection("salat-collection", "sourcethatdoesntexist") must throwAn[PlayException]
} }
} }

// tests with a single URI defined
"start with URI only" in {
running(fakeAppFromURI) {
salat must beAnInstanceOf[SalatPlugin]
}
}

"return a MongoCollection with URI only" in {
running(fakeAppFromURI) {
val col = salat.collection("salat-collection")
col must beAnInstanceOf[MongoCollection]
}
}

"set replicasets with URI only" in {
running(fakeAppFromURI) {
def s = fakeAppFromURI.plugin[SalatPlugin].get
s must beAnInstanceOf[SalatPlugin]
val source = s.source("default")
source.hosts must equalTo(List(new ServerAddress("127.0.0.1", 27017)))
}
}

// tests with multiple URIs defined
"start with URIs only" in {
running(fakeAppFromURIs) {
salat must beAnInstanceOf[SalatPlugin]
}
}

"return a MongoCollection with URIs only" in {
running(fakeAppFromURIs) {
val col = salat.collection("salat-collection")
col must beAnInstanceOf[MongoCollection]
}
}

"set replicasets with URIs only" in {
running(fakeAppFromURIs) {
def s = fakeAppFromURIs.plugin[SalatPlugin].get
s must beAnInstanceOf[SalatPlugin]
val source = s.source("default")
source.hosts must equalTo(List(new ServerAddress("127.0.0.1", 27017), new ServerAddress("mongodb.org", 1337)))
}
}

// tests with multiple authenticated URIs defined
"start with authenticated URIs only" in {
running(fakeAppFromURIsWithAuth) {
salat must beAnInstanceOf[SalatPlugin]
}
}

"return a MongoCollection with authenticated URIs only" in {
running(fakeAppFromURIsWithAuth) {
val col = salat.collection("salat-collection")
col must beAnInstanceOf[MongoCollection]
}
}

"set replicasets with authenticated URIs only" in {
running(fakeAppFromURIsWithAuth) {
def s = fakeAppFromURIsWithAuth.plugin[SalatPlugin].get
s must beAnInstanceOf[SalatPlugin]
val source = s.source("default")
source.hosts must equalTo(List(new ServerAddress("127.0.0.1", 27017),
new ServerAddress("mongodb.org", 1337),
new ServerAddress("192.168.88.99", 27000)
))
}
}

"should propagate authentication credentials" in {
running(fakeAppFromURIsWithAuth) {
def s = fakeAppFromURIsWithAuth.plugin[SalatPlugin].get
s must beAnInstanceOf[SalatPlugin]
val source = s.source("default")
source.user must equalTo(Some("nyancat"))
source.password must equalTo(Some("ILoveMyKittens"))
}
}
} }
} }