Skip to content

Instantly share code, notes, and snippets.

@dbalduini
Last active August 29, 2015 13:56
Show Gist options
  • Save dbalduini/9239207 to your computer and use it in GitHub Desktop.
Save dbalduini/9239207 to your computer and use it in GitHub Desktop.
A Play Framework CachPlugin implementation for Memcached. @see https://github.com/couchbase/spymemcached
package plugins
import net.spy.memcached.ConnectionFactoryBuilder.Protocol
import net.spy.memcached.auth.{PlainCallbackHandler, AuthDescriptor}
import play.api.{PlayException, Application}
import play.api.cache.CachePlugin
import play.api.cache.CacheAPI
import net.spy.memcached._
import net.spy.memcached.transcoders.{SerializingTranscoder, Transcoder}
class MemcachedCachePlugin(app: Application) extends CachePlugin {
lazy val namespace = app.configuration.getString("cache.memcached.namespace")
lazy val client: MemcachedClient = {
val host = app.configuration.getString("cache.memcached.host")
val user = app.configuration.getString("cache.memcached.user")
val pass = app.configuration.getString("cache.memcached.pass")
val addr = host.map(AddrUtil.getAddresses).getOrElse(
throw new PlayException("MemcachedCachePlugin Initialization Error",
"Could not find cache.memcached.host at application.conf."))
(user, pass) match {
case(Some(u), Some(p)) =>
val ad = new AuthDescriptor(Array("PLAIN"), new PlainCallbackHandler(u, p))
val factory = new ConnectionFactoryBuilder().setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build()
new MemcachedClient(factory, addr)
case _ => new MemcachedClient(addr)
}
}
lazy val cache = new MemcachedCacheAPI(client, namespace)
override def enabled =
app.configuration.getString("cache.memcached.plugin").getOrElse("enabled") != "disabled"
override def onStart() {
cache
}
lazy val api: CacheAPI = cache
}
class MemcachedCacheAPI(client: MemcachedClient, namespace: Option[String]) extends CacheAPI {
val thirtyDays = 2592000 // Max supported caching time for Memcached
def namespaced(key: String) = namespace.map( _ + ":" + key).getOrElse(key)
def set(key: String, value: Any, expiration: Int): Unit = {
if (!key.isEmpty) {
if (expiration > 0) client.set(namespaced(key), expiration, value.toString)
else client.set(namespaced(key), thirtyDays, value)
}
}
def get(key: String): Option[String] = {
if (key.isEmpty) None
else Option(client.get[String](namespaced(key), new StringTranscoder))
}
def remove(key: String): Unit = {
if (!key.isEmpty) client delete namespaced(key)
}
}
sealed class StringTranscoder extends Transcoder[String] {
private val delegate = new SerializingTranscoder()
def asyncDecode(d: CachedData) = delegate.asyncDecode(d)
def decode(d: CachedData) = delegate.decode(d) match {
case data: String => data
case _ => throw new ClassCastException
}
def encode(data: String) = delegate.encode(data)
def getMaxSize: Int = delegate.getMaxSize
}
@dbalduini
Copy link
Author

resolvers += "Spy" at "http://files.couchbase.com/maven2/"

libraryDependencies += "spy" % "spymemcached" % "2.8.12",

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