All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
kalix.scalasdk.impl.action.ActionEffectImpl.scala Maven / Gradle / Ivy
/*
* Copyright 2024 Lightbend 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 kalix.scalasdk.impl.action
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import kalix.javasdk
import kalix.scalasdk.{ DeferredCall, Metadata, SideEffect }
import kalix.scalasdk.action.Action
import kalix.scalasdk.impl.ScalaDeferredCallAdapter
import kalix.scalasdk.impl.ScalaSideEffectAdapter
import io.grpc.Status
private[scalasdk] object ActionEffectImpl {
sealed abstract class PrimaryEffect[T] extends Action.Effect[T] {
def toJavaSdk: javasdk.action.Action.Effect[T]
override def addSideEffect(sideEffects: SideEffect*): Action.Effect[T] =
withSideEffects(internalSideEffects() ++ sideEffects)
override def addSideEffects(sideEffects: Seq[SideEffect]): Action.Effect[T] =
withSideEffects(internalSideEffects() ++ sideEffects)
protected def internalSideEffects(): Seq[SideEffect]
protected def withSideEffects(sideEffects: Seq[SideEffect]): Action.Effect[T]
def canHaveSideEffects: Boolean = true
}
final case class ReplyEffect[T](msg: T, metadata: Option[Metadata], internalSideEffects: Seq[SideEffect])
extends PrimaryEffect[T] {
def isEmpty: Boolean = false
protected def withSideEffects(sideEffects: Seq[SideEffect]): ReplyEffect[T] =
copy(internalSideEffects = sideEffects)
override def toJavaSdk: javasdk.impl.action.ActionEffectImpl.PrimaryEffect[T] = {
val metadataUnwrapped: Option[javasdk.Metadata] = metadata.map(_.impl)
val sideEffects = internalSideEffects.map { case ScalaSideEffectAdapter(se) => se }
javasdk.impl.action.ActionEffectImpl.ReplyEffect(msg, metadataUnwrapped, sideEffects)
}
}
final case class AsyncEffect[T](effect: Future[Action.Effect[T]], internalSideEffects: Seq[SideEffect])
extends PrimaryEffect[T] {
def isEmpty: Boolean = false
protected def withSideEffects(sideEffects: Seq[SideEffect]): AsyncEffect[T] =
copy(internalSideEffects = sideEffects)
private def convertEffect(effect: Action.Effect[T]): Future[javasdk.action.Action.Effect[T]] = {
effect match {
case eff: AsyncEffect[T] =>
// FIXME? the Future may wrap another AsyncEffect.
// Should we put a limit on it to avoid a stackoverflow?
eff.effect.flatMap(convertEffect)(ExecutionContext.parasitic)
case eff: PrimaryEffect[T] => Future.successful(eff.toJavaSdk)
}
}
override def toJavaSdk: javasdk.impl.action.ActionEffectImpl.PrimaryEffect[T] = {
val sideEffects = internalSideEffects.map { case ScalaSideEffectAdapter(javasdkSideEffect) => javasdkSideEffect }
val javaEffect = effect.flatMap(convertEffect)(ExecutionContext.parasitic)
javasdk.impl.action.ActionEffectImpl.AsyncEffect(javaEffect, sideEffects)
}
}
final case class ForwardEffect[T](serviceCall: DeferredCall[_, T], internalSideEffects: Seq[SideEffect])
extends PrimaryEffect[T] {
def isEmpty: Boolean = false
protected def withSideEffects(sideEffects: Seq[SideEffect]): ForwardEffect[T] =
copy(internalSideEffects = sideEffects)
override def toJavaSdk: javasdk.impl.action.ActionEffectImpl.PrimaryEffect[T] = {
val sideEffects = internalSideEffects.map { case ScalaSideEffectAdapter(se) => se }
val javaDeferredCall = serviceCall match {
case ScalaDeferredCallAdapter(jdc) => jdc
}
javasdk.impl.action.ActionEffectImpl.ForwardEffect(javaDeferredCall, sideEffects)
}
}
final case class ErrorEffect[T](
description: String,
statusCode: Option[Status.Code],
internalSideEffects: Seq[SideEffect])
extends PrimaryEffect[T] {
def isEmpty: Boolean = false
protected def withSideEffects(sideEffects: Seq[SideEffect]): ErrorEffect[T] =
copy(internalSideEffects = sideEffects)
override def toJavaSdk: javasdk.impl.action.ActionEffectImpl.PrimaryEffect[T] = {
val sideEffects = internalSideEffects.map { case ScalaSideEffectAdapter(jse) => jse }
javasdk.impl.action.ActionEffectImpl
.ErrorEffect(description, statusCode, sideEffects)
}
}
def IgnoreEffect[T](): PrimaryEffect[T] = IgnoreEffect.asInstanceOf[PrimaryEffect[T]]
final case object IgnoreEffect extends PrimaryEffect[Nothing] {
def isEmpty: Boolean = true
override def internalSideEffects() = Nil
override def canHaveSideEffects: Boolean = false
protected def withSideEffects(sideEffect: Seq[SideEffect]): PrimaryEffect[Nothing] =
throw new IllegalArgumentException("adding side effects to is not allowed.")
override def toJavaSdk = javasdk.impl.action.ActionEffectImpl.IgnoreEffect()
}
object Builder extends Action.Effect.Builder {
override def reply[S](message: S): Action.Effect[S] = ReplyEffect(message, None, Nil)
override def reply[S](message: S, metadata: Metadata): Action.Effect[S] = ReplyEffect(message, Some(metadata), Nil)
override def forward[S](serviceCall: DeferredCall[_, S]): Action.Effect[S] = ForwardEffect(serviceCall, Nil)
override def error[S](description: String): Action.Effect[S] =
ErrorEffect(description, None, Nil)
override def error[S](description: String, statusCode: Status.Code): Action.Effect[S] =
if (statusCode.toStatus.isOk) throw new IllegalArgumentException("Cannot fail with a success status")
else ErrorEffect(description, Some(statusCode), Nil)
override def asyncReply[S](futureMessage: Future[S]): Action.Effect[S] =
asyncReply(futureMessage, Metadata.empty)
override def asyncReply[S](futureMessage: Future[S], metadata: Metadata): Action.Effect[S] =
AsyncEffect(futureMessage.map(s => Builder.reply[S](s, metadata))(ExecutionContext.parasitic), Nil)
override def asyncEffect[S](futureEffect: Future[Action.Effect[S]]): Action.Effect[S] =
AsyncEffect(futureEffect, Nil)
override def ignore[S]: Action.Effect[S] =
IgnoreEffect()
}
def builder(): Action.Effect.Builder = Builder
}