How to unsubscribe topic from PubSubRegistry in lagom - scala

class WebSocketUtils(pubSub: PubSubRegistry)(implicit ec: ExecutionContext) {
def topic(id: String) = pubSub.refFor(TopicIdString)
def subscribe(id: String) =
topic(id).subscriber
def unsubscribe(id:String) = ??
}

Related

Reusablecode for db operations with dependency injection

I have multiple actors managing data models that are written to a mongo db.
object LevelManager {
val collectionName = "levels"
}
#Singleton
class LevelManager #Inject()(
val reactiveMongoApi: ReactiveMongoApi) extends Actor with ActorLogging with InjectedActorSupport {
def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection](LevelManager.collectionName))
override def receive: Receive = {
case msg:GetById =>
var level = collection.flatMap(c => c.find(Json.obj("_id" -> msg.id), Option.empty[JsObject]).one[LevelModel].map {
result =>
logger.info( result )
}
}
}
This works fine, but this db code is used in every actor and i did not manage to have it only once. I'm not sure if this is even a clever way, too. It derived from older scala times without dependency injection, where everything was put in an object trait.
So i'm looking for a trait or something, with basic db io handling
Edit: Before dependency injection i was able to use a trait like this:
trait BaseModel[T] {
val collectionName: String
val db = ReactiveMongoPlugin.db
def load(id: Long)(implicit fmt: Format[T]) = {
val coll = db.collection[JSONCollection](collectionName)
coll.find(Json.obj("_id" -> id)).one[T]
}
def loadAll()(implicit fmt: Format[T]) = {
val coll = db.collection[JSONCollection](collectionName)
coll.find(Json.obj()).cursor[T].collect[Vector]()
}
def save(id: Long, model: T)(implicit fmt: Format[T]) = {
val coll = db.collection[JSONCollection](collectionName)
val doc = Json.toJson(model).as[JsObject] + ("_id" -> Json.toJson(id))
coll.save(doc).map { lastError =>
if (!lastError.ok) Logger.error(lastError.message)
lastError.ok
}
}
I ended in creating a trait with def collection: Future[JSONCollection] and i'm now able to access the db my favorite db functions. This was my goal and makes life so much better. But i'm unsettled from the recent feedback here, if this has any disadvantages.
trait DBStuff[T] {
def collection: Future[JSONCollection]
def log: LoggingAdapter
def save(id: String, model: T)(implicit fmt: Format[T]) = {
val doc:JsObject = Json.toJson(model).as[JsObject] + ("_id" -> Json.toJson(id))
collection.flatMap(_.update.one(Json.obj("_id" -> id), doc, true)).map(lastError => if (!lastError.ok) log.warning(s"Mongo LastError: %s".format(lastError)))
}
def loadOne(id: String)(implicit fmt: Format[T]): Future[Option[T]] = loadOne( Json.obj("_id" -> id) )
def loadOne(obj: JsObject, projection:Option[JsObject] = None )(implicit fmt: Format[T]): Future[Option[T]] = {
collection.flatMap(_.find( obj, projection).one[T].map {
result =>
result
}.recover {
case err => log.error(s"DB Loading Error: $err")
None
})
}
def loadAll()(implicit fmt: Format[T]):Future[Vector[T]] = {
loadAll(Json.obj(), None )
}
def loadAll( obj: JsObject, projection:Option[JsObject] = None)(implicit fmt: Format[T]):Future[Vector[T]] = {
collection.flatMap(_.find(obj, projection ).cursor[T]().collect[Vector](Int.MaxValue, Cursor.FailOnError()).map {
result => result
}.recover {
case err =>
log.error(s"DB Loading Error: $err")
Vector.empty
})
}
...
}
#Singleton
class TaskManager #Inject()(
val reactiveMongoApi: ReactiveMongoApi
) extends Actor with ActorLogging with InjectedActorSupport with DBStuff[TaskModel] {
def collection: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection](TaskManager.collectionName))
override def preStart() = {
loadAll() map {
result =>
//What ever
}
}

Play framework WSClient testing

I have a service class in my code, for example, UserService. It has a WSClient member which makes calls to a web service. I would like to write test cases for the UserService methods.
I did some research on testing WSClient but did not find any use case like mine. Should I establish a live test service, or do mocking? This is another question.
class UserService #Inject()(ws: WSClient) {
def getUser(userId: UUID) = {// some code}
def createUser(obj: User) = {// another piece of code}
These methods use the WSClient to call the web service endpoints.
I would like to write test cases for these methods. Which is the best, setting up a test service and call that or mocking the WSClient?
I have created a CustomWSClient, CustomWSRequest and CustomWSResponse for testing purposes as follows.
package unittest
import play.api.http.Writeable
import play.api.libs.iteratee.Enumerator
import play.api.libs.json.{JsValue, Json}
import play.api.libs.ws._
import scala.concurrent.Future
import scala.xml.Elem
class CustomWSClient extends WSClient {
var t: ResponseObject = new ResponseObject(Json.toJson("Success"), Map("trial" -> Seq("value")), 200)
override def underlying[T]: T = underlying.asInstanceOf[T]
override def url(url: String): WSRequest = {
var c: CustomWSRequest = CustomWSRequest(url, t)
c.setResponse(t)
c
}
override def close(): Unit = {}
def setResponse(t: ResponseObject) = {
this.t = t
}
}
case class CustomWSRequest(inputUrl: String, t: ResponseObject) extends WSRequest {
override val url: String = inputUrl
override def withHeaders(hdrs: (String, String)*): WSRequest = { this }
override def withAuth(username: String, password: String, scheme: WSAuthScheme): WSRequest = { this }
override def withQueryString(parameters: (String, String)*): WSRequest = { this }
override def execute(): Future[WSResponse] = { Future.successful(CustomWSResponse(t)) }
override def sign(calc: WSSignatureCalculator): WSRequest = { this }
override def stream(): Future[(WSResponseHeaders, Enumerator[Array[Byte]])] = null
override def withVirtualHost(vh: String): WSRequest = { this }
override def withMethod(method: String): WSRequest = { this }
override def withRequestTimeout(timeout: Long): WSRequest = { this }
override def withProxyServer(proxyServer: WSProxyServer): WSRequest = { this }
override def withFollowRedirects(follow: Boolean): WSRequest = { this }
override def withBody(body: WSBody): WSRequest = { this }
override def get(): Future[WSResponse] = { Future.successful(CustomWSResponse(t)) }
override def post[T](body: T)(implicit wrt: Writeable[T]) = { Future.successful(CustomWSResponse(t)) }
//override def put[T](body: T)(implicit wrt: Writeable[T]) = {Future.successful( CustomWSResponse(t))}
def setResponse(t: ResponseObject) = {
t
}
override val calc: Option[WSSignatureCalculator] = None
override val queryString: Map[String, Seq[String]] = Map("trial" -> Seq("value"))
override val method: String = "TestMethod"
override val followRedirects: Option[Boolean] = None
override val body: WSBody = null
override val requestTimeout: Option[Int] = None
override val virtualHost: Option[String] = None
override val proxyServer: Option[WSProxyServer] = None
override val auth: Option[(String, String, WSAuthScheme)] = None
override val headers: Map[String, Seq[String]] = Map("trial" -> Seq("value"))
}
case class CustomWSResponse(t: ResponseObject) extends play.api.libs.ws.WSResponse {
def allHeaders: Map[String, Seq[String]] = { t.headers }
def statusText: String = { "success" }
def underlying[T]: T = underlying.asInstanceOf[T]
def body: String = { t.json.toString() }
def header(key: String): Option[String] = Option(t.headers.get(key).headOption.get.apply(0))
def cookie(name: String): Option[WSCookie] = Some(CustomWSCookie("test"))
def status: Int = { t.status }
def json: JsValue = t.json
override def cookies: Seq[WSCookie] = Seq(CustomWSCookie("test"))
override def xml: Elem = null
override def bodyAsBytes: Array[Byte] = null
}
case class CustomWSCookie(t: String) extends play.api.libs.ws.WSCookie {
override def underlying[T]: T = this.underlying
override def domain: String = "test"
override def name: Option[String] = Some("test")
override def value: Option[String] = Some("test")
override def path: String = "test"
override def expires: Option[Long] = Some(2L)
override def maxAge: Option[Int] = Some(5)
override def secure: Boolean = true
}
case class ResponseObject(json: JsValue, headers: Map[String, Seq[String]], status: Int)
I have created a mock where ever ws object is used.
class TranslationsActorSpec extends ServiceOneAppPerSuite with LazyLogging {
override val ws = mock[CustomWSClient]
val mockWSRequest = mock[CustomWSRequest]
val mockWSResponse = mock[CustomWSResponse]
when(ws.url("https://getCallToMyService")) thenReturn (mockWSRequest)
when(mockWSRequest.withHeaders(
"Authorization" -> "token somevalue"
)) thenReturn (mockWSRequest)
when(mockWSRequest.get()) thenReturn (Future.successful(mockWSResponse))
when(mockWSResponse.status) thenReturn (200)
//write your testcase and pass ws object to it, it will get the mocked response for the service call
}

Akka Kafka Custom Serializer

I'm using Akka Kafka (Scala) and want to send custom objects.
class TweetsSerializer extends Serializer[Seq[MyCustomType]] {
override def configure(configs: util.Map[String, _], isKey: Boolean): Unit = ???
override def serialize(topic: String, data: Seq[MyCustomType]): Array[Byte] = ???
override def close(): Unit = ???
}
How can i correctly write my own serializer ? And, what should i do with field config ?
I would use the StringSerializer, I mean, I´d convert all my types to string before produce them. However that works:
case class MyCustomType(a: Int)
class TweetsSerializer extends Serializer[Seq[MyCustomType]] {
private var encoding = "UTF8"
override def configure(configs: java.util.Map[String, _], isKey: Boolean): Unit = {
val propertyName = if (isKey) "key.serializer.encoding"
else "value.serializer.encoding"
var encodingValue = configs.get(propertyName)
if (encodingValue == null) encodingValue = configs.get("serializer.encoding")
if (encodingValue != null && encodingValue.isInstanceOf[String]) encoding = encodingValue.asInstanceOf[String]
}
override def serialize(topic: String, data: Seq[MyCustomType]): Array[Byte] =
try
if (data == null) return null
else return {
data.map { v =>
v.a.toString
}
.mkString("").getBytes("UTF8")
}
catch {
case e: UnsupportedEncodingException =>
throw new SerializationException("Error when serializing string to byte[] due to unsupported encoding " + encoding)
}
override def close(): Unit = Unit
}
}
object testCustomKafkaSerializer extends App {
implicit val producerConfig = {
val props = new Properties()
props.setProperty("bootstrap.servers", "localhost:9092")
props.setProperty("key.serializer", classOf[StringSerializer].getName)
props.setProperty("value.serializer", classOf[TweetsSerializer].getName)
props
}
lazy val kafkaProducer = new KafkaProducer[String, Seq[MyCustomType]](producerConfig)
// Create scala future from Java
private def publishToKafka(id: String, data: Seq[MyCustomType]) = {
kafkaProducer
.send(new ProducerRecord("outTopic", id, data))
.get()
}
val input = MyCustomType(1)
publishToKafka("customSerializerTopic", Seq(input))
}

Type parameters and inheritance in Scala

Is there a simple way to return a concrete type in an override method? And what about creating an instance of a concrete implementation? And calling chained methods implemented in the concrete class, so they return a correct type, too? I have a solution (based on https://stackoverflow.com/a/14905650) but I feel these things should be simpler.
There are many similar questions, but everyone's case is a little different, so here is another example (shortened from https://github.com/valdanylchuk/saiml/tree/master/src/main/scala/saiml/ga). When replying, if possible, please check if the whole code block compiles with your suggested change, because there are subtle cascading effects. I could not make this work with the "curiously recurring template pattern", for example (not that I find it nicer).
import scala.reflect.ClassTag
import scala.util.Random
abstract class Individual(val genome: String) {
type Self
def this() = this("") // please override with a random constructor
def crossover(that: Individual): Self
}
class HelloGenetic(override val genome: String) extends Individual {
type Self = HelloGenetic
def this() = this(Random.alphanumeric.take("Hello, World!".length).mkString)
override def crossover(that: Individual): HelloGenetic = {
val newGenome = this.genome.substring(0, 6) + that.genome.substring(6)
new HelloGenetic(newGenome)
}
}
class Population[A <: Individual {type Self = A} :ClassTag]( val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.tabulate(size)(_ => implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A])
def tournamentSelect(): A = individuals.head // not really, skipped
def evolve: Population[A] = {
val nextGen = (0 until size).map { _ =>
val parent1: A = tournamentSelect()
val parent2: A = tournamentSelect()
val child: A = parent1.crossover(parent2)
child
}.toVector
new Population(size, tournamentSize, Some(nextGen))
}
}
class Genetic[A <: Individual {type Self = A} :ClassTag](populationSize: Int, tournamentSize: Int) {
def optimize(maxGen: Int, maxMillis: Long): Individual = {
val first = new Population[A](populationSize, tournamentSize)
val optPop = (0 until maxGen).foldLeft(first) { (pop, _) => pop.evolve }
optPop.individuals.head
}
}
The CRTP version is
abstract class Individual[A <: Individual[A]](val genome: String) {
def this() = this("") // please override with a random constructor
def crossover(that: A): A
}
class HelloGenetic(override val genome: String) extends Individual[HelloGenetic] {
def this() = this(Random.alphanumeric.take("Hello, World!".length).mkString)
override def crossover(that: HelloGenetic): HelloGenetic = {
val newGenome = this.genome.substring(0, 6) + that.genome.substring(6)
new HelloGenetic(newGenome)
}
}
class Population[A <: Individual[A] :ClassTag]( val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.tabulate(size)(_ => implicitly[ClassTag[A]].runtimeClass.newInstance.asInstanceOf[A])
def tournamentSelect(): A = individuals.head // not really, skipped
def evolve: Population[A] = {
val nextGen = (0 until size).map { _ =>
val parent1: A = tournamentSelect()
val parent2: A = tournamentSelect()
val child: A = parent1.crossover(parent2)
child
}.toVector
new Population(size, tournamentSize, Some(nextGen))
}
}
class Genetic[A <: Individual[A] :ClassTag](populationSize: Int, tournamentSize: Int) {
def optimize(maxGen: Int, maxMillis: Long): Individual[A] = {
val first = new Population[A](populationSize, tournamentSize)
val optPop = (0 until maxGen).foldLeft(first) { (pop, _) => pop.evolve }
optPop.individuals.head
}
}
which compiles. For creating the instances, I'd suggest just passing functions:
class Population[A <: Individual[A]](val size: Int,
tournamentSize: Int, makeIndividual: () => A, givenIndividuals: Option[Vector[A]] = None) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.fill(size)(makeIndividual())
...
}
If you want to pass them implicitly, you can easily do so:
trait IndividualFactory[A] {
def apply(): A
}
class HelloGenetic ... // remove def this()
object HelloGenetic {
implicit val factory: IndividualFactory[HelloGenetic] = new IndividualFactory[HelloGenetic] {
def apply() = new HelloGenetic(Random.alphanumeric.take("Hello, World!".length).mkString)
}
}
class Population[A <: Individual[A]](val size: Int,
tournamentSize: Int, givenIndividuals: Option[Vector[A]] = None)
(implicit factory: IndividualFactory[A]) {
val individuals: Vector[A] = givenIndividuals getOrElse
Vector.fill(size)(factory())
...
}

Finding right type class to use

I'm trying to implement a type class solution for error handling in a Play application. What I want is to have some type class instances representing some validated (caught) errors and a default type class instance for any unvalidated (uncaught) errors.
I don't know if this is possible, but here's what I have so far:
trait ResponseError[E] {
def report(e: E)(implicit logger: Logger): Unit
def materialize(e: E): Result
}
trait ValidatedError[E <: Throwable] extends ResponseError[E] {
def report(e: E)(implicit logger: Logger): Unit =
ResponseError.logError(e)
}
trait UnvalidatedError[E <: Throwable] extends ResponseError[E] {
def report(e: E)(implicit logger: Logger): Unit = {
ResponseError.logError(e)
UnvalidatedError.notify(e)
}
}
object ResponseError {
def logError(e: Throwable)(implicit logger: Logger): Unit =
logger.error(e.getMessage)
}
object ValidatedError {
import java.util.concurrent.{ExecutionException, TimeoutException}
implicit val executionError = new ValidatedError[ExecutionException] {
def materialize(e: E): Result =
play.api.mvc.Results.BadRequest
}
implicit val timeoutError = new ValidatedError[TimeoutException] {
def materialize(e: E): Result =
play.api.mvc.Results.RequestTimeout
}
}
object UnvalidatedError {
implicit uncaughtError = new UnvalidatedError[Throwable] {
def materialize(e: E): Result =
play.api.mvc.Results.ServiceUnavailable
}
private def notify(e: Throwable) = ??? // send email notification
}
However how can I make sure to try my ValidatedError type class instances first, before falling back to my UnvalidatedError type class instance?
There you go. See my comment for details.
import java.util.concurrent.{TimeoutException, ExecutionException}
type Result = String
val badRequest: Result = "BadRequest"
val requestTimeout: Result = "RequestTimeout"
val serviceUnavailable: Result = "ServiceUnavailable"
class Logger {
def error(s: String) = println(s + "\n")
}
trait ResponseError[E] {
def report(e: E)(implicit logger: Logger): Unit
def materialize(e: E): Result
}
trait ValidatedError[E <: Throwable] extends UnvalidatedError[E] {
override def report(e: E)(implicit logger: Logger): Unit =
ResponseError.logError(e, validated = true)
}
trait UnvalidatedError[E <: Throwable] extends ResponseError[E] {
def report(e: E)(implicit logger: Logger): Unit = {
ResponseError.logError(e, validated = false)
UnvalidatedError.notify(e)
}
}
object ResponseError {
def logError(e: Throwable, validated: Boolean)(implicit logger: Logger): Unit =
logger.error({
validated match {
case true => "VALIDATED : "
case false => "UNVALIDATED : "
}
} + e.getMessage)
}
object ValidatedError {
import java.util.concurrent.{ExecutionException, TimeoutException}
implicit def executionError[E <: ExecutionException] = new ValidatedError[E] {
def materialize(e: E): Result =
badRequest
}
implicit def timeoutError[E <: TimeoutException] = new ValidatedError[E] {
def materialize(e: E): Result =
requestTimeout
}
}
object UnvalidatedError {
implicit def uncaughtError[E <: Throwable] = new UnvalidatedError[E] {
def materialize(e: E): Result =
serviceUnavailable
}
private def notify(e: Throwable) = println("Sending email: " + e) // send email notification
}
def testTypeclass[E](e: E)(implicit logger: Logger, ev: ResponseError[E]): Unit ={
ev.report(e)
}
import ValidatedError._
import UnvalidatedError._
implicit val logger: Logger = new Logger
val executionErr = new ExecutionException(new Throwable("execution exception!"))
testTypeclass(executionErr)
val timeoutErr = new TimeoutException("timeout exception!")
testTypeclass(timeoutErr)
val otherErr = new Exception("other exception!")
testTypeclass(otherErr)
Output:
VALIDATED : java.lang.Throwable: execution exception!
VALIDATED : timeout exception!
UNVALIDATED : other exception!
Sending email: java.lang.Exception: other exception!