All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.wordnik.mongo.connection.MongoDBConnectionManager.scala Maven / Gradle / Ivy

The newest version!
package com.wordnik.mongo.connection

import com.mongodb._

import java.net.UnknownHostException
import java.util.StringTokenizer
import java.util.logging.Logger

import scala.collection.JavaConversions._
import scala.collection.mutable._

object SchemaType {
  val READ_ONLY = 1
  val READ_WRITE = 2
}

object MongoDBConnectionManager {
  val LOGGER = Logger.getLogger(MongoDBConnectionManager.getClass.getName)
  val mongos = new HashMap[String, Member]
  val pool = new HashMap[String, List[DBServer]]

  @throws(classOf[PersistenceException])
  def getConnection(schemaName: String, schemaType: Int): DB = {
    LOGGER.finest("getting from, key: " + schemaName + ", schemaType: " + schemaType)

    val snl = schemaName.toLowerCase
    if (!pool.contains(snl)) throw new PersistenceException("no configurations found for " + schemaName)

    val servers = pool(snl)
    var output: Option[DB] = None

    schemaType match {
      //	read write => rs or master
      case SchemaType.READ_WRITE => {
        servers.foreach(server => {
          if (server.replicationType == Member.RS || server.replicationType == Member.M) {
            server.username match {
              case Some(user) => {
                if (!server.db.isAuthenticated)
                  server.db.authenticate(user, server.password.toCharArray)
              }
              case _ =>
            }
            output = Some(server.db)
          }
        })
      }
      case _ => {
        //  slaves => rs or slave unless only one master
        servers.foreach(server => {
          if (server.replicationType == Member.RS || server.replicationType == Member.S) {
            server.username match {
              case Some(user) => {
                if (!server.db.isAuthenticated)
                  server.db.authenticate(user, server.password.toCharArray)
              }
              case _ => {
                server.db.setReadPreference(ReadPreference.secondaryPreferred)
              }
            }
            output = Some(server.db)
          }
        })
        //this means there are no slaves so it is ok to get connection from any server
        if (output == None) {
          //	user master anyway
          output = Some(servers(0).db)
        }
      }
    }

    output match {
      case Some(db) => db
      case _ => throw new PersistenceException("no configurations found for " + schemaName)
    }
  }

  def getOplog(friendlyName: String, host: String, username: String, password: String): Option[DBCollection] = {
    val db = getConnection(friendlyName, host, "local", username, password, SchemaType.READ_WRITE)
    val servers = pool.get(friendlyName)
    var coll: Option[DBCollection] = None
    servers.get.foreach(server => {
      if (server.replicationType == Member.RS)
        coll = Some(server.db.getCollection("oplog.rs"))
      else if (server.replicationType == Member.M)
        coll = Some(server.db.getCollection("oplog.$main"))
    })
    coll
  }

  @throws(classOf[PersistenceException])
  def getConnection(schemaName: String, h: String, schema: String, u: String, pw: String, schemaType: Int): DB = {
    if (h.indexOf(":") > 0) getConnection(schemaName, h.split(":")(0), h.split(":")(1).toInt, schema, u, pw, schemaType)
    else getConnection(schemaName, h, 27017, schema, u, pw, schemaType)
  }

  @throws(classOf[PersistenceException])
  def getConnection(friendlyName: String, h: String, p: Int, schema: String, u: String, pw: String, schemaType: Int): DB = {
    var host: String = h
    var port = p
    val username = {
      if (null != u && u.trim != "") Some(u)
      else None
    }
    val password = {
      if (null == pw) ""
      else pw
    }
    try {
      if (null == host) host = "localhost"
      if (port <= 0) port = 27017

      LOGGER.finest("getting connection to " + host + ":" + port + "/" + schema + " with username: " + username + ", password: " + password)

      val schemaId = (host + ":" + port + ":" + schema).toLowerCase
      val db = mongos.contains(schemaId) match {
        case true => {
          LOGGER.finest("getting " + schemaId + " from map")
          val db = mongos(schemaId).mongo.getDB(schema)
          val replicationType = detectReplicationType(db, username, password)
          LOGGER.finest("all known servers: " + db.getMongo.getServerAddressList)
          addServer(friendlyName, schema, db: DB, username, password, replicationType)
          db
        }
        case _ => {
          LOGGER.finest("creating " + schemaId)
          val sa = new ServerAddress(host, port)
          var mongo = new Mongo(sa)

          var db = mongo.getDB(schema)
          val replicationType = detectReplicationType(db, username, password)

          if (replicationType == Member.RS) {
            mongo = new Mongo(List(sa))
            db = mongo.getDB(schema)
          }
          mongos += schemaId -> new Member(replicationType, mongo)
          LOGGER.finest("schemaName: " + friendlyName + ", schemaId: " + schemaId)
          addServer(friendlyName, schema, db: DB, username, password, replicationType)
          db
        }
      }
      db
    } catch {
      case e: Exception => {
        LOGGER.severe("can't get connection to " + host + ":" + port + "/" + schema + " with username " + username + ", password " + password);
        throw new PersistenceException(e);
      }
    }
  }

  def detectReplicationType(db: DB, username: Option[String], password: String) = {
    try {
      //	check it
      var stat: String = null
      username match {
        case Some(username) => {
          db.authenticate(username, password.toCharArray)
          stat = db.command("isMaster").toString
          if (stat.indexOf("\"ismaster\" : true") > 0) Member.M
          else Member.S
        }
        case _ => {
          stat = db.command("isMaster").toString
          if (stat.indexOf("setName") > 0) {
            //  is a replica set
            LOGGER.finest("detected replica set")
            Member.RS
          } else {
            if (stat.indexOf("\"ismaster\" : true") > 0) Member.M
            else if (stat.indexOf("\"ismaster\" : false") > 0) Member.S
            else Member.UNKNOWN
          }
        }
      }
    } catch {
      case e: Exception => {
        e.printStackTrace
        Member.UNKNOWN
      }
      case _: Throwable =>
        throw new PersistenceException("Failed to detect replication type")
    }
  }

  def addServer(friendlyName: String, schema: String, db: DB, username: Option[String], password: String, replicationType: Int) = {
    val snl = friendlyName.toLowerCase
    if (!pool.contains(snl)) {
      pool += snl -> List[DBServer]()
    }
    val serverList = new ListBuffer[DBServer]
    pool(snl).foreach(server => serverList += server)

    val dbServer = new DBServer(db, username, password, replicationType)
    if(!serverList.contains(dbServer)) serverList += dbServer
    pool += snl -> serverList.toList
    LOGGER.finest("adding to pool, key: " + snl + ", db: " + db)
  }
}

class DBServer(val db: DB, val username: Option[String], val password: String, val replicationType: Int) {

  override def toString: String = {
    new StringBuilder().append("db: ").append(db).append(", replType: ").append(replicationType).toString
  }

  override def equals(other:Any):Boolean = {
    other match {
      case that:DBServer => (this.db.getMongo.getAddress == that.db.getMongo.getAddress &&
                                this.replicationType == that.replicationType)
      case _ => false
    }
  }
}

object Member {
  val RS = 1
  val M = 2
  val S = 3
  val UNKNOWN = 4
}

class Member(val memberType: Int, val mongo: Mongo)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy