Skip to content

Commit

Permalink
Merge pull request #132 from KarelCemus/httpcontext_backport
Browse files Browse the repository at this point in the history
Backport of the support of Http.Context in JavaRedis
  • Loading branch information
KarelCemus committed Nov 12, 2017
2 parents 3cf6fd6 + 3bf5a17 commit b77f2cd
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 7 deletions.
11 changes: 8 additions & 3 deletions src/main/scala/play/api/cache/redis/impl/JavaRedis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package play.api.cache.redis.impl
import java.util.concurrent.{Callable, CompletionStage}
import javax.inject.{Inject, Singleton}

import scala.compat.java8.FutureConverters
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.reflect.ClassTag
Expand All @@ -22,15 +21,16 @@ import play.api.cache.redis._
private[ impl ] class JavaRedis @Inject()( internal: CacheAsyncApi, environment: Environment, connector: RedisConnector ) extends play.cache.AsyncCacheApi {

import JavaRedis._
import connector.context

def set( key: String, value: scala.Any, expiration: Int ): CompletionStage[ Done ] =
set( key, value, expiration.seconds ).toJava

def set( key: String, value: scala.Any ): CompletionStage[ Done ] =
set( key, value, Duration.Inf ).toJava

def set( key: String, value: scala.Any, duration: Duration ): Future[ Done ] =
def set( key: String, value: scala.Any, duration: Duration ): Future[ Done ] = {
import connector.context

Future.sequence(
Seq(
// set the value
Expand All @@ -41,6 +41,7 @@ private[ impl ] class JavaRedis @Inject()( internal: CacheAsyncApi, environment:
).map {
case Seq( done, _ ) => done
}
}

def remove( key: String ): CompletionStage[ Done ] = internal.remove( key ).toJava

Expand All @@ -54,6 +55,9 @@ private[ impl ] class JavaRedis @Inject()( internal: CacheAsyncApi, environment:
getOrElse[ T ]( key, Some( block ), duration = expiration.seconds )

def getOrElse[ T ]( key: String, callable: Option[ Callable[ CompletionStage[ T ] ] ], duration: Duration = Duration.Inf ): CompletionStage[ T ] = {
import play.core.j.HttpExecutionContext
// save the HTTP context if any and restore it later for orElse clause
implicit val context = HttpExecutionContext.fromThread( connector.context )
// get the tag and decode it
def getClassTag = internal.get[ String ]( s"classTag::$key" )
def decodeClassTag( name: String ): ClassTag[ T ] = if ( name == null ) ClassTag.Null.asInstanceOf[ ClassTag[ T ] ] else ClassTag( environment.classLoader.loadClass( name ) )
Expand All @@ -80,6 +84,7 @@ private[ impl ] class JavaRedis @Inject()( internal: CacheAsyncApi, environment:
}

private[ impl ] object JavaRedis {
import scala.compat.java8.FutureConverters

private implicit class Java8Compatibility[ T ]( val future: Future[ T ] ) extends AnyVal {
@inline def toJava: CompletionStage[ T ] = FutureConverters.toJava( future )
Expand Down
27 changes: 25 additions & 2 deletions src/test/scala/play/api/cache/redis/impl/JavaCacheSpec.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package play.api.cache.redis.impl

import java.util.Date
import java.util.concurrent.Callable
import java.util.concurrent.atomic.AtomicInteger

import play.api.cache.redis.{Redis, SimpleObject}
import play.mvc.Http
import play.test.Helpers

import org.joda.time.DateTime
import org.specs2.mutable.Specification
Expand All @@ -13,9 +16,9 @@ import org.specs2.mutable.Specification
*/
class JavaCacheSpec extends Specification with Redis {

private type Cache = play.cache.CacheApi
private type Cache = play.cache.SyncCacheApi

private val Cache = injector.instanceOf[ play.cache.CacheApi ]
private val Cache = injector.instanceOf[ play.cache.SyncCacheApi ]

private val prefix = "java"

Expand Down Expand Up @@ -59,6 +62,26 @@ class JavaCacheSpec extends Specification with Redis {
counter.get mustEqual 1
}

"getOrElseUpdate" in {
Cache.get[ String ]( s"$prefix-test-getOrElseUpdate" ) must beNull
val orElse = new Callable[ String ] { def call( ) = "value" }
Cache.getOrElseUpdate[ String ]( s"$prefix-test-getOrElseUpdate", orElse ) mustEqual "value"
Cache.get[ String ]( s"$prefix-test-getOrElseUpdate" ) mustEqual "value"
}

"getOrElseUpdate uses HttpContext" in {
Cache.get[ String ]( s"$prefix-test-getOrElseUpdate-2" ) must beNull
val request = Helpers.fakeRequest().path( "request-path" ).build()
val context = Helpers.httpContext( request )
Http.Context.current.set( context )
val orElse = new Callable[ String ] {
def call( ) = Http.Context.current().request().path()
}
Http.Context.current().request().path() mustEqual "request-path"
Cache.getOrElseUpdate[ String ]( s"$prefix-test-getOrElseUpdate-2", orElse ) mustEqual "request-path"
Cache.get[ String ]( s"$prefix-test-getOrElseUpdate-2" ) mustEqual "request-path"
}

"distinct different keys" in {
val counter = new AtomicInteger( 0 )
Cache.getOrElseCounting( s"$prefix-test-7A" )( counter ) mustEqual "value"
Expand Down
4 changes: 2 additions & 2 deletions src/test/scala/play/api/cache/redis/impl/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ package object impl extends LowPriorityImplicits {
def apply[ S <: Any ]( value: Expectable[ S ] ): MatchResult[ S ] = result( test = true, value.description + " is Unit", value.description + " is not Unit", value.evaluate )
}

implicit class JavaAccumulatorCache( val cache: play.cache.CacheApi ) extends AnyVal {
implicit class JavaAccumulatorCache( val cache: play.cache.SyncCacheApi ) extends AnyVal {
private type Accumulator = AtomicInteger

/** invokes internal getOrElse but it accumulate invocations of orElse clause in the accumulator */
def getOrElseCounting( key: String )( accumulator: Accumulator ) = cache.getOrElse[ String ]( key, new Callable[ String ] {
def getOrElseCounting( key: String )( accumulator: Accumulator ) = cache.getOrElseUpdate[ String ]( key, new Callable[ String ] {
override def call( ): String = {
// increment miss counter
accumulator.incrementAndGet()
Expand Down

0 comments on commit b77f2cd

Please sign in to comment.