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

com.twitter.storehaus.mongodb.MongoStore.scala Maven / Gradle / Ivy

/*
 * Copyright 2014 Twitter inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.twitter.storehaus.mongodb

import java.util.concurrent.Executors

import com.twitter.storehaus.Store
import com.twitter.util.{ Future, FuturePool }

import com.mongodb.casbah.Imports._

import scala.reflect.Manifest

/**
 *  @author Bin Lan
 */

trait MongoValue[T]

object MongoValue {
  implicit object MongoInt extends MongoValue[Int]
  implicit object MongoLong extends MongoValue[Long]
  implicit object MongoDouble extends MongoValue[Double]
  implicit object MongoBoolean extends MongoValue[Boolean]
  implicit object MongoString extends MongoValue[String]
  implicit object MongoObject extends MongoValue[DBObject]
  implicit object MongoDate extends MongoValue[java.util.Date]
}

object MongoStore {

  def apply[K: MongoValue, V: MongoValue: Manifest](
      client: MongoClient,
      dbName: String,
      colName: String,
      keyName: String = "key",
      valueName: String = "value",
      backgroundIndex: Boolean = false,
      threadNumber: Int = Runtime.getRuntime.availableProcessors): MongoStore[K, V] = {
    new MongoStore[K, V](client, dbName, colName, keyName, valueName, backgroundIndex, threadNumber)
  }
}

/**
 * A simple implementation for storehaus using MongoDB as backend storage.
 */
class MongoStore[K: MongoValue, V: MongoValue: Manifest] (
    val client: MongoClient,
    val dbName: String,
    val colName: String,
    val keyName: String,
    val valueName: String,
    val backgroundIndex: Boolean,
    val threadNumber: Int)
  extends Store[K, V] {

  protected val db = client(dbName)
  protected val col = db(colName)
  // make sure we build an index
  col.ensureIndex(MongoDBObject(keyName -> 1), MongoDBObject("name" -> (keyName + "Idx"), "background" -> backgroundIndex))
  protected val futurePool = FuturePool(Executors.newFixedThreadPool(threadNumber))

  override def put(kv: (K, Option[V])): Future[Unit] = {
    kv match {
      case (key, Some(value)) => futurePool {
        col.update(MongoDBObject(keyName -> key), MongoDBObject(keyName -> key, valueName -> value), upsert = true)
      }
      case (key, None) => futurePool {
        col.remove(MongoDBObject(keyName -> key))
      }
    }
  }

  override def get(key: K): Future[Option[V]] = futurePool {
    col.findOne(MongoDBObject(keyName -> key)).flatMap { valueObject => {
        getValue(valueObject)
      }
    }
  }

  protected def getValue(valueObject: MongoDBObject): Option[V] = {
    valueObject.getAs[V](valueName) match {
      case None => {
        if (valueObject.get(valueName) == None) None
        else throw new ClassCastException("Cannot convert %s to %s".format(valueObject.get(valueName).getClass(), manifest[V]))
      }
      case Some(value) => {
        if (getManifest().isInstance(value)) Some(value)
        else throw new ClassCastException("Cannot convert %s to %s".format(value.getClass(), manifest[V]))
      }
    }
  }

  protected def getManifest() = {
    manifest[V] match {
      case Manifest.Int => classOf[java.lang.Integer]
      case Manifest.Long => classOf[java.lang.Long]
      case Manifest.Double => classOf[java.lang.Double]
      case Manifest.Boolean => classOf[java.lang.Boolean]
      case m => m.erasure
    }
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy