Skip to content
This repository

MongoURI support #8

Merged
merged 1 commit into from almost 2 years ago

2 participants

Juan M Uys Leon Radley
Leon Radley
Owner
leon commented May 22, 2012

Great, I'll have a look at merging this in the upcoming 1.0.4 release :)

Leon Radley leon merged commit ae278a7 into from May 22, 2012
Leon Radley leon closed this May 22, 2012
Leon Radley
Owner
leon commented May 22, 2012

I've implemented mongoURI now, I've pushed 1.0.4-SNAPSHOT
Give it a go and tell me if anything isn't working as expected.

Thanks to the specs, there should't be any surprises :)

Leon Radley
Owner
leon commented May 22, 2012

I've also added travis-ci

http://travis-ci.org/#!/leon/play-salat

Juan M Uys
opyate commented May 22, 2012

Brilliant, thanks Leon :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

May 22, 2012
Juan M Uys Add MongoURI support ae278a7
This page is out of date. Refresh to see the latest.
83  src/main/scala/se/radley/plugin/salat/SalatPlugin.scala
@@ -3,7 +3,7 @@ package se.radley.plugin.salat
3 3
 import play.api._
4 4
 import play.api.mvc._
5 5
 import play.api.Play.current
6  
-import com.mongodb.casbah.{WriteConcern, MongoCollection, MongoConnection}
  6
+import com.mongodb.casbah.{WriteConcern, MongoCollection, MongoConnection, MongoURI}
7 7
 import com.mongodb.ServerAddress
8 8
 
9 9
 class SalatPlugin(app: Application) extends Plugin {
@@ -39,26 +39,71 @@ class SalatPlugin(app: Application) extends Plugin {
39 39
       "/" + db
40 40
     }
41 41
   }
  42
+  
  43
+  /**
  44
+   * Extracts host as String and port as Int from host string
  45
+   * and defaults port to 27017 if it doesn't exist.
  46
+   * 
  47
+   * E.g. localhost:9999 returns (localhost, 9999)
  48
+   * E.g. localhost returns (localhost, 27017)
  49
+   */
  50
+  def hostAndPort(host: String): (String, Int) = host.contains(':') match {
  51
+    case true => {
  52
+      val Array(h,p) = host.split(':')
  53
+      (h,p.toInt)
  54
+    }
  55
+    case false => (host, 27017)
  56
+  }
42 57
 
43 58
   lazy val sources: Map[String, MongoSource] = configuration.subKeys.map { sourceKey =>
44 59
     val source = configuration.getConfig(sourceKey).getOrElse(Configuration.empty)
45  
-    val db = source.getString("db").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".db", "db missing for source[" + sourceKey + "]"))
46  
-
47  
-    // Simple config
48  
-    val host = source.getString("host").getOrElse("127.0.0.1")
49  
-    val port = source.getInt("port").getOrElse(27017)
50  
-    val user:Option[String] = source.getString("user")
51  
-    val password:Option[String] = source.getString("password")
52  
-
53  
-    // Replica set config
54  
-    val hosts: List[ServerAddress] = source.getConfig("replicaset").map { replicaset =>
55  
-      replicaset.subKeys.map { hostKey =>
56  
-        val c = replicaset.getConfig(hostKey).get
57  
-        val host = c.getString("host").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".replicaset", "host missing for replicaset in source[" + sourceKey + "]"))
58  
-        val port = c.getInt("port").getOrElse(27017)
59  
-        new ServerAddress(host, port)
60  
-      }.toList
61  
-    }.getOrElse(List.empty)
  60
+    
  61
+    // support MongoURI as per http://www.mongodb.org/display/DOCS/Connections
  62
+    val (host, port, user, password, hosts, db) = source.getString("uri").map{ uri => {
  63
+      val all = MongoURI(uri)
  64
+      val (host,port) = hostAndPort(all.hosts(0))
  65
+      val user = all.username match {
  66
+        case "null" => None
  67
+        case null => None
  68
+        case s => Some(s)
  69
+      }
  70
+      
  71
+      val password = all.password match {
  72
+        case null => None
  73
+        case s => all.password.foldLeft("")(_ + _.toString) match {
  74
+          case "" => None
  75
+          case s => Some(s)
  76
+        }
  77
+      }
  78
+      
  79
+      // to List[ServerAddress]
  80
+      val hosts = all.hosts.map(host => {
  81
+        val (h,p) = hostAndPort(host)
  82
+        new ServerAddress(h, p)
  83
+      })
  84
+      
  85
+      (host, port, user, password, hosts.toList, all.database)
  86
+    }}.getOrElse{
  87
+      val db = source.getString("db").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".db", "db missing for source[" + sourceKey + "]"))
  88
+
  89
+      // Simple config
  90
+      val host = source.getString("host").getOrElse("127.0.0.1")
  91
+      val port = source.getInt("port").getOrElse(27017)
  92
+      val user:Option[String] = source.getString("user")
  93
+      val password:Option[String] = source.getString("password")
  94
+
  95
+      // Replica set config
  96
+      val hosts: List[ServerAddress] = source.getConfig("replicaset").map { replicaset =>
  97
+        replicaset.subKeys.map { hostKey =>
  98
+          val c = replicaset.getConfig(hostKey).get
  99
+          val host = c.getString("host").getOrElse(throw configuration.reportError("mongodb." + sourceKey + ".replicaset", "host missing for replicaset in source[" + sourceKey + "]"))
  100
+          val port = c.getInt("port").getOrElse(27017)
  101
+          new ServerAddress(host, port)
  102
+        }.toList
  103
+      }.getOrElse(List.empty)
  104
+      
  105
+      (host, port, user, password, hosts, db)
  106
+    }
62 107
 
63 108
     val writeConcern = WriteConcern.valueOf(source.getString("writeconcern", Some(Set("fsyncsafe", "replicassafe", "safe", "normal"))).getOrElse("safe"))
64 109
 
@@ -66,7 +111,7 @@ class SalatPlugin(app: Application) extends Plugin {
66 111
     if (hosts.isEmpty)
67 112
       sourceKey -> MongoSource(List(new ServerAddress(host, port)), db, writeConcern, user, password)
68 113
     else
69  
-      sourceKey -> MongoSource(hosts, db, writeConcern)
  114
+      sourceKey -> MongoSource(hosts, db, writeConcern, user, password)
70 115
   }.toMap
71 116
 
72 117
   override def enabled = !configuration.subKeys.isEmpty
103  src/test/scala/se/radley/plugin/salat/SalatSpec.scala
@@ -29,6 +29,27 @@ object SalatSpec extends Specification {
29 29
       ("mongodb.default.replicaset.host2.host" -> "10.0.0.2")
30 30
     )
31 31
   )
  32
+  
  33
+  lazy val fakeAppFromURI = FakeApplication(
  34
+    additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"),
  35
+    additionalConfiguration = Map(
  36
+      ("mongodb.default.uri" -> "mongodb://127.0.0.1:27017/salat-test")
  37
+    )
  38
+  )
  39
+  
  40
+  lazy val fakeAppFromURIs = FakeApplication(
  41
+    additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"),
  42
+    additionalConfiguration = Map(
  43
+      ("mongodb.default.uri" -> "mongodb://127.0.0.1:27017,mongodb.org:1337/salat-test")
  44
+    )
  45
+  )
  46
+  
  47
+  lazy val fakeAppFromURIsWithAuth = FakeApplication(
  48
+    additionalPlugins = Seq("se.radley.plugin.salat.SalatPlugin"),
  49
+    additionalConfiguration = Map(
  50
+      ("mongodb.default.uri" -> "mongodb://nyancat:ILoveMyKittens@127.0.0.1:27017,mongodb.org:1337,192.168.88.99:27000/salat-test")
  51
+    )
  52
+  )
32 53
 
33 54
   def salat = fakeApp.plugin[SalatPlugin].get
34 55
 
@@ -76,5 +97,87 @@ object SalatSpec extends Specification {
76 97
         salat.collection("salat-collection", "sourcethatdoesntexist") must throwAn[PlayException]
77 98
       }
78 99
     }
  100
+    
  101
+    // tests with a single URI defined
  102
+    "start with URI only" in {
  103
+      running(fakeAppFromURI) {
  104
+        salat must beAnInstanceOf[SalatPlugin]
  105
+      }
  106
+    }
  107
+
  108
+    "return a MongoCollection with URI only" in {
  109
+      running(fakeAppFromURI) {
  110
+        val col = salat.collection("salat-collection")
  111
+        col must beAnInstanceOf[MongoCollection]
  112
+      }
  113
+    }
  114
+    
  115
+    "set replicasets with URI only" in {
  116
+      running(fakeAppFromURI) {
  117
+        def s = fakeAppFromURI.plugin[SalatPlugin].get
  118
+        s must beAnInstanceOf[SalatPlugin]
  119
+        val source = s.source("default")
  120
+        source.hosts must equalTo(List(new ServerAddress("127.0.0.1", 27017)))
  121
+      }
  122
+    }
  123
+    
  124
+    // tests with multiple URIs defined
  125
+    "start with URIs only" in {
  126
+      running(fakeAppFromURIs) {
  127
+        salat must beAnInstanceOf[SalatPlugin]
  128
+      }
  129
+    }
  130
+
  131
+    "return a MongoCollection with URIs only" in {
  132
+      running(fakeAppFromURIs) {
  133
+        val col = salat.collection("salat-collection")
  134
+        col must beAnInstanceOf[MongoCollection]
  135
+      }
  136
+    }
  137
+    
  138
+    "set replicasets with URIs only" in {
  139
+      running(fakeAppFromURIs) {
  140
+        def s = fakeAppFromURIs.plugin[SalatPlugin].get
  141
+        s must beAnInstanceOf[SalatPlugin]
  142
+        val source = s.source("default")
  143
+        source.hosts must equalTo(List(new ServerAddress("127.0.0.1", 27017), new ServerAddress("mongodb.org", 1337)))
  144
+      }
  145
+    }
  146
+    
  147
+    // tests with multiple authenticated URIs defined
  148
+    "start with authenticated URIs only" in {
  149
+      running(fakeAppFromURIsWithAuth) {
  150
+        salat must beAnInstanceOf[SalatPlugin]
  151
+      }
  152
+    }
  153
+
  154
+    "return a MongoCollection with authenticated URIs only" in {
  155
+      running(fakeAppFromURIsWithAuth) {
  156
+        val col = salat.collection("salat-collection")
  157
+        col must beAnInstanceOf[MongoCollection]
  158
+      }
  159
+    }
  160
+    
  161
+    "set replicasets with authenticated URIs only" in {
  162
+      running(fakeAppFromURIsWithAuth) {
  163
+        def s = fakeAppFromURIsWithAuth.plugin[SalatPlugin].get
  164
+        s must beAnInstanceOf[SalatPlugin]
  165
+        val source = s.source("default")
  166
+        source.hosts must equalTo(List(new ServerAddress("127.0.0.1", 27017),
  167
+            new ServerAddress("mongodb.org", 1337),
  168
+            new ServerAddress("192.168.88.99", 27000)
  169
+        ))
  170
+      }
  171
+    }
  172
+    
  173
+    "should propagate authentication credentials" in {
  174
+      running(fakeAppFromURIsWithAuth) {
  175
+        def s = fakeAppFromURIsWithAuth.plugin[SalatPlugin].get
  176
+        s must beAnInstanceOf[SalatPlugin]
  177
+        val source = s.source("default")
  178
+        source.user must equalTo(Some("nyancat"))
  179
+        source.password must equalTo(Some("ILoveMyKittens"))
  180
+      }
  181
+    }
79 182
   }
80 183
 }
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.