All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.akkaserverless.javasdk.impl.replicatedentity.ReplicatedEntityRouter.scala Maven / Gradle / Ivy

/*
 * Copyright 2021 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 com.akkaserverless.javasdk.impl.replicatedentity

import com.akkaserverless.javasdk.impl.EntityExceptions.ProtocolException
import com.akkaserverless.javasdk.impl.replicatedentity.ReplicatedEntityEffectImpl.UpdateData
import java.util.Optional

import com.akkaserverless.javasdk.replicatedentity.{ CommandContext, ReplicatedEntity }
import com.akkaserverless.javasdk.impl.{ AnySupport, EntityExceptions }
import com.akkaserverless.protocol.replicated_entity.ReplicatedEntityDelta
import com.akkaserverless.replicatedentity.ReplicatedData

object ReplicatedEntityRouter {
  final case class CommandResult(effect: ReplicatedEntity.Effect[_])

  final case class CommandHandlerNotFound(commandName: String) extends RuntimeException
}

/**
 * @tparam D
 *   the replicated data type for the entity
 *
 * 

Not for manual user extension or interaction. * *

The concrete ReplicatedEntityRouter is generated for the specific entities defined in Protobuf. */ abstract class ReplicatedEntityRouter[D <: ReplicatedData, E <: ReplicatedEntity[D]](protected val entity: E) { import ReplicatedEntityRouter._ private var data: D = _ private def internalData: InternalReplicatedData = data.asInstanceOf[InternalReplicatedData] /** INTERNAL API */ // "public" api against the impl/testkit final def _internalInitialData(initialData: Option[InternalReplicatedData], anySupport: AnySupport): Unit = initialData match { case Some(d) => data = d.asInstanceOf[D] case _ => val dataFactory = new ReplicatedDataFactoryImpl(anySupport) val emptyData = entity.emptyData(dataFactory) require(emptyData ne null, "Initial empty data for a replicated entity cannot be null") data = emptyData } /** INTERNAL API */ // "public" api against the impl/testkit final def _internalApplyDelta(entityId: String, delta: ReplicatedEntityDelta): Unit = { data = internalData.applyDelta .applyOrElse( delta.delta, { noMatch: ReplicatedEntityDelta.Delta => throw ProtocolException( entityId, s"Received delta ${noMatch.value.getClass} which doesn't match the expected replicated data type: ${internalData.name}") }) .asInstanceOf[D] } /** INTERNAL API */ // "public" api against the impl/testkit final def _internalHasDelta: Boolean = internalData.hasDelta /** INTERNAL API */ // "public" api against the impl/testkit final def _internalGetAndResetDelta: ReplicatedEntityDelta.Delta = { val delta = internalData.getDelta data = internalData.resetDelta().asInstanceOf[D] delta } /** INTERNAL API */ // "public" api against the impl/testkit final def _internalHandleCommand(commandName: String, command: Any, context: CommandContext): CommandResult = { val commandEffect = try { entity._internalSetCommandContext(Optional.of(context)) // Note: replicated data objects are currently mutable, so we pass a copy to the command. // If the update effect is not used then we still have the old replicated data (without delta). handleCommand(commandName, data, command, context) .asInstanceOf[ReplicatedEntityEffectImpl[D, Any]] } catch { case CommandHandlerNotFound(name) => throw new EntityExceptions.EntityException( context.entityId(), context.commandId(), commandName, s"No command handler found for command [$name] on ${entity.getClass}") } finally { entity._internalSetCommandContext(Optional.empty()) } if (!commandEffect.hasError) { commandEffect.primaryEffect match { case UpdateData(newData) => require(newData ne null, "update effect with null data is not allowed") data = newData.asInstanceOf[D] case _ => } } CommandResult(commandEffect) } protected def handleCommand( commandName: String, data: D, command: Any, context: CommandContext): ReplicatedEntity.Effect[_] def entityClass: Class[_] = entity.getClass }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy