/ParaBond/src/scaly/parabond/util/MongoHelper.scala
Scala | 292 lines | 143 code | 70 blank | 79 comment | 4 complexity | 1f1f555f344fae14b491adc0e95090f0 MD5 | raw file
- /*
- * Copyright (c) Scaly Contributors
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Scaly Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package scaly.parabond.util
- import com.mongodb.casbah.MongoCursor
- import scaly.parabond.entry.SimpleBond
- import com.mongodb.BasicDBObject
- import com.mongodb.BasicDBList
- import scala.collection.JavaConverters._
- import scala.util.Random
- import com.mongodb.casbah.MongoConnection
- import com.mongodb.casbah.commons.MongoDBObject
- import scala.actors._
- import Actor._
- import com.mongodb.casbah.MongoCollection
-
- /** Converts mongo cursor to a simple bond */
- object MongoHelper {
- /** Sets the mongo host */
- val host: String = getHost
-
- /** Connects to the parabond DB */
- // val mongo = MongoConnection("127.0.0.1")("parabond")
- val mongo = MongoConnection(host)("parabond")
-
- /** Initialize the random number generator */
- val ran = new Random(0)
-
- case class Intermediate(portfId: Int, list : List[SimpleBond])
- case class Intermediate2(bonds: List[SimpleBond])
-
- /**
- * Loads a list of 2-tuples of portfolios x list of bonds
- */
- def loadPortfs(n : Int) : List[(Int,List[SimpleBond])] = {
- // Connect to the portfolio collection
- val portfsCollecton = mongo("Portfolios")
-
- val input = (1 to n).foldLeft(List[(Int,List[SimpleBond])] ()) { (list, pid) =>
- // Select a portfolio
- val lottery = ran.nextInt(100000) + 1
-
- // Retrieve the portfolio
- val portfsQuery = MongoDBObject("id" -> lottery)
-
- val portfsCursor = portfsCollecton.find(portfsQuery)
-
- // Get the bonds in the portfolio
- val bondIds = MongoHelper.asList(portfsCursor, "instruments")
-
- // Connect to the bonds collection
- val bondsCollection = mongo("Bonds")
-
- val bonds = bondIds.foldLeft(List[SimpleBond]()) { (bonds, id) =>
- // Get the bond from the bond collection
- val bondQuery = MongoDBObject("id" -> id)
-
- val bondCursor: MongoCursor = bondsCollection.find(bondQuery)
-
- val bond = MongoHelper.asBond(bondCursor)
-
- // The price into the aggregate sum
- bonds ++ List(bond)
- }
-
- list ++ List((lottery,bonds))
- }
-
- input
- }
-
- /**
- * Parallel load the portfolios and bonds into memory (actor-based).
- */
- def loadPortfsParallel(n : Int) : List[(Int,List[SimpleBond])] = {
- val portfsCollection = mongo("Portfolios")
-
- val caller = self
-
- (1 to n).foreach { p =>
-
- // Select a portfolio
- val lottery = ran.nextInt(100000) + 1
-
- actor {
- caller ! fetchBonds(lottery, portfsCollection)
- }
- }
-
- var list = List[(Int, List[SimpleBond])]()
-
- (1 to n).foreach { p =>
- receive {
- case Intermediate(portfId, bonds) =>
- list = list ++ List((portfId, bonds))
- }
- }
-
- list
-
- }
-
- /**
- * Loads portfolios x bonds into memory
- */
- def loadPortfsPar(n: Int): List[(Int,List[SimpleBond])] = {
- val portfsCollection = mongo("Portfolios")
-
- val lotteries = for(i <- 0 to n) yield ran.nextInt(100000)+1
-
- val list = lotteries.par.foldLeft (List[(Int,List[SimpleBond])]())
- { (portfIdBonds,portfId) =>
- val intermediate = fetchBonds(portfId,portfsCollection)
-
- (portfId,intermediate.list) :: portfIdBonds
- }
-
- list
- }
-
- /**
- * Fetch the bonds from the database.
- */
- def fetchBonds(portfId: Int,portfsCollection: MongoCollection): Intermediate = {
- // Retrieve the portfolio
- val portfsQuery = MongoDBObject("id" -> portfId)
-
- val portfsCursor = portfsCollection.find(portfsQuery)
-
- // Get the bonds in the portfolio
- val bondIds = MongoHelper.asList(portfsCursor, "instruments")
-
- // Connect to the bonds collection
- val bondsCollection = mongo("Bonds")
-
- val bonds = bondIds.foldLeft(List[SimpleBond]()) { (bonds, id) =>
- // Get the bond from the bond collection
- val bondQuery = MongoDBObject("id" -> id)
-
- val bondCursor: MongoCursor = bondsCollection.find(bondQuery)
-
- val bond = MongoHelper.asBond(bondCursor)
-
- // The price into the aggregate sum
- bonds ++ List(bond)
- }
-
- // Method below runs out of semaphores on mongo
- // val bonds = fetchBondsParallel(bondIds,bondsCollection)
-
- Intermediate(portfId,bonds)
- }
-
- /**
- * Fetches bonds in parallel from the database
- */
- def fetchBondsParallel(bondIds : List[Int], bondsColledtion : MongoCollection) : List[SimpleBond] = {
- val caller = self
-
- bondIds.foreach { id =>
- actor {
- val bondQuery = MongoDBObject("id" -> id)
-
- val bondCursor: MongoCursor = bondsColledtion.find(bondQuery)
-
- val bond = MongoHelper.asBond(bondCursor)
-
- println("got "+id)
- caller ! bond
- }
- }
-
- var bonds = List[SimpleBond]( )
- (1 to bondIds.size).foreach { p =>
- receive {
- case bond : SimpleBond =>
-
- bonds = bonds ++ List(bond)
- }
- }
-
- bonds
- }
-
- /**
- * Converts the mongo cursor to a bond -- assuming the query cursor
- * as a single bond
- */
- def asBond(cursor: MongoCursor) : SimpleBond = {
- val cur = cursor.map { p =>
- p match {
- case b : BasicDBObject =>
- val id = b.get("id").toString.toInt
-
- val coupon = b.get("coupon").toString.toDouble
-
- val freq = b.get("freq").toString.toInt
-
- val tenor = b.get("tenor").toString.toDouble
-
- val maturity = b.get("maturity").toString.toDouble
-
- new SimpleBond(id,coupon,freq,tenor,maturity)
-
- }
- }
-
- cur.next
- }
-
- /** Converts mongo cursor to scala list of int objects */
- def asList(cursor: MongoCursor,field : String) : List[Int] = {
- val cur = cursor.map { p =>
- // Get mongo ids which is a BasicDBList -- but Scala
- // can't handle this with FP so we need to convert it
- // an immutable list that FP can handle
- val ids = p.get(field)
-
- ids match {
- case listAsJava : BasicDBList =>
- val listInteger = listAsJava.asScala
-
- val list = listInteger.map { p =>
- p match {
- case intAsJava : java.lang.Integer =>
- intAsJava.toInt
- }
- }
-
- list.toList
- case _ =>
- null
- }
- }
-
- // cur is an Iterator[List[Int]] of size 1
- cur.next
- }
-
- /**
- * Updates the price of a portfolio with the price.
- */
- def updatePrice(portfId: Int, price: Double) {
- // Retrive the portfolio
- val portfsCollecton = mongo("Portfolios")
-
- val portfsQuery = MongoDBObject("id" -> portfId)
-
- val portfsCursor : MongoCursor = portfsCollecton.find(portfsQuery)
-
- val portf = portfsCursor.next
-
- // Set the price
- portf.put("price", price)
-
- // Write-back the portfolio
- mongo("Portfolios").save(portf)
- }
-
- /**
- * Gets the mongo host
- * */
- def getHost : String = {
- val host = System.getProperty("host")
-
- if(host != null) host else "127.0.0.1"
- }
-
- }