finatra 八歩目 ScalaCache

# キャッシュ機能
欲しいですよね。
scala cacheでググったら出てくるScalaCache使ってみます。

https://github.com/cb372/scalacache

# Moduleにする

Google Guava、Memcached、Ehcache、Redis、Caffeine
という選択肢がありますが、今回はEhcacheを利用します。

```scala:CacheModule.scala
import com.google.inject.{ Provides, Singleton }
import com.twitter.inject.TwitterModule
import net.sf.ehcache.CacheManager

import scalacache._
import ehcache._

/**
 * Created by Fumiyasu on 2016/07/17.
 */
object CacheModule extends TwitterModule {

  val cacheManager = CacheManager.getInstance()

  @Provides @Singleton
  def provideCache() = {
    val underlying = cacheManager.getCache("sample") // xmlに定義した名前
    ScalaCache(EhcacheCache(underlying))
  }

}
```

```xml:ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true" />

    <cache name="sample"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           overflowToDisk="true" />
</ehcache>
```

# CacheModuleを追加

```scala:HelloWorldServer.scala
import com.twitter.finagle.http.{ Request, Response }
import com.twitter.finatra.http.HttpServer
import com.twitter.finatra.http.filters.{ CommonFilters, LoggingMDCFilter, TraceIdMDCFilter }
import com.twitter.finatra.http.routing.HttpRouter
import controllers.{ GroupController, OAuth2Controller }
import modules.{ CacheModule, QuillDatabaseModule }

object HelloWorldServerMain extends HelloWorldServer

class HelloWorldServer extends HttpServer {

  /*
   * Since Heroku only supports a single port per service,
   * we disable the Admin HTTP Server
   */
  override val disableAdminHttpServer = true

  override val defaultFinatraHttpPort = ":9000"
  override val defaultHttpPort = 9001

  override def modules = Seq(QuillDatabaseModule, CacheModule)

  override def configureHttp(router: HttpRouter) {
    router
      .filter[LoggingMDCFilter[Request, Response]]
      .filter[TraceIdMDCFilter[Request, Response]]
      .filter[CommonFilters]
      .add[HelloWorldController]
      .add[GroupController]
      .add[OAuth2Controller]
  }
}
```

# 使うところはこんな感じ

```scala:OAuth2Controller.scala

import javax.inject.Inject

import com.twitter.finagle.http._
import com.twitter.finatra.http.Controller
import models.User
import twitter4j.{ Twitter, TwitterFactory }
import utils.Id64

import scalacache._
import scalacache.serialization.InMemoryRepr

/**
 * Created by Fumiyasu on 2016/07/04.
 */
class OAuth2Controller @Inject() (implicit val cache: ScalaCache[InMemoryRepr]) extends Controller {

  get("/api/v1/request") { request: Request =>

    try {
      val twitter = TwitterFactory.getSingleton
      twitter.setOAuthAccessToken(null)
      val url = twitter.getOAuthRequestToken.getAuthenticationURL

      response.ok(url)
    } catch {
      case e => response.badRequest
    }
  }

  get("/callback") { request: Request =>
    val twitter = TwitterFactory.getSingleton

    request.containsParam("oauth_verifier") match {
      case true => {
        val oauthToken = request.getParam("oauth_token")
        val oauthVerifier = request.getParam("oauth_verifier")
        val accessToken = twitter.getOAuthAccessToken(oauthVerifier)
        val user = User(accessToken.getUserId, accessToken.getScreenName)
        val cookie = new Cookie("userName", user.userName)
        cookie.isSecure_=(true)

        val userCacheId = Id64.nextAscId().toString

        sync.caching(userCacheId) {
          user
        }

        info(s"cache: ${sync.get(userCacheId)}")

        //        cacheApi.set(userCacheId, user)
        response.ok.cookie(cookie).cookie("userCacheId", userCacheId)
      }
      case false => response.ok
    }
  }
}
```

# consoleに出力
```
handshake-api 11:35:51.457 [finagle/netty3-2] DEBUG scalacache.ehcache.EhcacheCache - Cache hit for key 7545048605208146
42
handshake-api 11:35:51.457 [finagle/netty3-2] INFO  controllers.OAuth2Controller - cache: Some(User(106109400,FScoward))
```

簡単ですね