diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/AclDescriptorFactory.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/AclDescriptorFactory.scala index 88e145400..c2c892a29 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/AclDescriptorFactory.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/AclDescriptorFactory.scala @@ -16,7 +16,6 @@ import kalix.{ Annotations => KalixAnnotations } import org.slf4j.LoggerFactory import java.util.Collections -import scala.PartialFunction.condOpt /** * INTERNAL API @@ -121,23 +120,6 @@ private[impl] object AclDescriptorFactory { fd.toProto } - def serviceLevelAclAnnotation(component: Class[_], default: Option[ProtoAcl] = None): Option[kalix.ServiceOptions] = { - - val javaAclAnnotation = component.getAnnotation(classOf[Acl]) - - def buildServiceOpts(acl: ProtoAcl): kalix.ServiceOptions = { - kalix.ServiceOptions - .newBuilder() - .setAcl(acl) - .build() - } - - condOpt(javaAclAnnotation, default) { - case (aclAnnotation, _) if aclAnnotation != null => buildServiceOpts(deriveProtoAnnotation(aclAnnotation)) - case (null, Some(acl)) => buildServiceOpts(acl) - } - } - def methodLevelAclAnnotation(method: Method): Option[kalix.MethodOptions] = { val javaAclAnnotation = method.getAnnotation(classOf[Acl]) diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptor.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptor.scala index 0daa35e93..6aa3c8718 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptor.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptor.scala @@ -4,39 +4,10 @@ package akka.javasdk.impl -import akka.javasdk.impl.reflection.ActionHandlerMethod -import akka.javasdk.impl.reflection.AnyJsonRequestServiceMethod -import akka.javasdk.impl.reflection.CombinedSubscriptionServiceMethod -import akka.javasdk.impl.reflection.CommandHandlerMethod -import akka.javasdk.impl.reflection.DeleteServiceMethod -import akka.javasdk.impl.reflection.ExtractorCreator -import akka.javasdk.impl.reflection.KalixMethod -import akka.javasdk.impl.reflection.NameGenerator -import akka.javasdk.impl.reflection.ParameterExtractor -import akka.javasdk.impl.reflection.ParameterExtractors -import akka.javasdk.impl.reflection.Reflect -import akka.javasdk.impl.reflection.ServiceMethod -import akka.javasdk.impl.reflection.SubscriptionServiceMethod -import akka.javasdk.impl.reflection.VirtualServiceMethod -import java.lang.reflect.ParameterizedType - -import AnySupport.ProtobufEmptyTypeUrl import akka.annotation.InternalApi -import akka.javasdk.annotations.ComponentId +import akka.javasdk.impl.reflection.KalixMethod import akka.javasdk.impl.serialization.JsonSerializer -import com.google.api.AnnotationsProto -import com.google.api.HttpRule -import com.google.protobuf.BytesValue -import com.google.protobuf.DescriptorProtos -import com.google.protobuf.DescriptorProtos.DescriptorProto -import com.google.protobuf.DescriptorProtos.FieldDescriptorProto -import com.google.protobuf.DescriptorProtos.MethodDescriptorProto -import com.google.protobuf.DescriptorProtos.MethodOptions -import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto import com.google.protobuf.Descriptors -import com.google.protobuf.Descriptors.FileDescriptor -import com.google.protobuf.Empty -import com.google.protobuf.{ Any => JavaPbAny } /** * The component descriptor is both used for generating the protobuf service descriptor to communicate the service type @@ -49,7 +20,7 @@ import com.google.protobuf.{ Any => JavaPbAny } private[impl] object ComponentDescriptor { def descriptorFor(component: Class[_], serializer: JsonSerializer): ComponentDescriptor = - ComponentDescriptorFactory.getFactoryFor(component).buildDescriptorFor(component, serializer, new NameGenerator) + ComponentDescriptorFactory.getFactoryFor(component).buildDescriptorFor(component, serializer) def apply(serializer: JsonSerializer, kalixMethods: Seq[KalixMethod]): ComponentDescriptor = { @@ -66,360 +37,6 @@ private[impl] object ComponentDescriptor { def apply(methods: Map[String, CommandHandler]): ComponentDescriptor = { new ComponentDescriptor(null, null, methods, null, null) } - - def apply( - nameGenerator: NameGenerator, - serializer: JsonSerializer, - serviceName: String, - serviceOptions: Option[kalix.ServiceOptions], - packageName: String, - kalixMethods: Seq[KalixMethod], - additionalMessages: Seq[ProtoMessageDescriptors] = Nil): ComponentDescriptor = { - - val otherMessageProtos: Seq[DescriptorProtos.DescriptorProto] = - additionalMessages.flatMap(pm => pm.mainMessageDescriptor +: pm.additionalMessageDescriptors) - - val grpcService = ServiceDescriptorProto.newBuilder() - grpcService.setName(serviceName) - - serviceOptions.foreach { serviceOpts => - val options = - DescriptorProtos.ServiceOptions - .newBuilder() - .setExtension(kalix.Annotations.service, serviceOpts) - .build() - grpcService.setOptions(options) - } - - def methodToNamedComponentMethod(kalixMethod: KalixMethod): NamedComponentMethod = { - - kalixMethod.validate() - - val (inputMessageName: String, extractors: Map[Int, ExtractorCreator], inputProto: Option[DescriptorProto]) = - kalixMethod.serviceMethod match { - case serviceMethod: CommandHandlerMethod => - val (inputProto, extractors) = - buildCommandHandlerMessageAndExtractors(nameGenerator, serviceMethod) - (inputProto.getName, extractors, Some(inputProto)) - - case actionHandlerMethod: ActionHandlerMethod => - val (inputProto, extractors) = - buildActionHandlerMessageAndExtractors(nameGenerator, actionHandlerMethod) - (inputProto.getName, extractors, Some(inputProto)) - - case anyJson: AnyJsonRequestServiceMethod => - if (anyJson.inputType == classOf[Array[Byte]]) { - (BytesValue.getDescriptor.getFullName, Map.empty[Int, ExtractorCreator], None) - } else { - (JavaPbAny.getDescriptor.getFullName, Map.empty[Int, ExtractorCreator], None) - } - - case _: DeleteServiceMethod => - (Empty.getDescriptor.getFullName, Map.empty[Int, ExtractorCreator], None) - } - - val grpcMethodName = nameGenerator.getName(kalixMethod.serviceMethod.methodName.capitalize) - val grpcMethodBuilder = - buildGrpcMethod( - grpcMethodName, - inputMessageName, - outputTypeName(kalixMethod), - kalixMethod.serviceMethod.streamIn, - kalixMethod.serviceMethod.streamOut) - - grpcMethodBuilder.setOptions(createMethodOptions(kalixMethod)) - - val grpcMethod = grpcMethodBuilder.build() - grpcService.addMethod(grpcMethod) - - NamedComponentMethod( - kalixMethod.serviceMethod, - serializer, - grpcMethodName, - extractors, - inputMessageName, - inputProto) - } - - val namedMethods: Seq[NamedComponentMethod] = kalixMethods.map(methodToNamedComponentMethod) - val inputMessageProtos: Set[DescriptorProtos.DescriptorProto] = namedMethods.flatMap(_.inputProto).toSet - - val fileDescriptor: Descriptors.FileDescriptor = - ProtoDescriptorGenerator.genFileDescriptor( - serviceName, - packageName, - grpcService.build(), - inputMessageProtos ++ otherMessageProtos) - - val methods: Map[String, CommandHandler] = - namedMethods.map { method => (method.grpcMethodName, method.toCommandHandler(fileDescriptor)) }.toMap - - val serviceDescriptor: Descriptors.ServiceDescriptor = - fileDescriptor.findServiceByName(grpcService.getName) - - new ComponentDescriptor(serviceName, packageName, methods, serviceDescriptor, fileDescriptor) - } - - private def outputTypeName(kalixMethod: KalixMethod): String = { - kalixMethod.serviceMethod.javaMethodOpt match { - case Some(javaMethod) => - javaMethod.getGenericReturnType match { - case parameterizedType: ParameterizedType => - val outputType = parameterizedType.getActualTypeArguments.head - if (outputType == classOf[Array[Byte]]) { - BytesValue.getDescriptor.getFullName - } else { - JavaPbAny.getDescriptor.getFullName - } - case _ => JavaPbAny.getDescriptor.getFullName - } - case None => JavaPbAny.getDescriptor.getFullName - } - } - - private def createMethodOptions(kalixMethod: KalixMethod): MethodOptions = { - - val methodOptions = MethodOptions.newBuilder() - - kalixMethod.serviceMethod match { - case commandHandlerMethod: CommandHandlerMethod => - val httpRuleBuilder = buildHttpRule(commandHandlerMethod) - - if (commandHandlerMethod.hasInputType) httpRuleBuilder.setBody("json_body") - - methodOptions.setExtension(AnnotationsProto.http, httpRuleBuilder.build()) - - case _ => //ignore - } - - kalixMethod.methodOptions.foreach(option => methodOptions.setExtension(kalix.Annotations.method, option)) - methodOptions.build() - } - - // intermediate format that references input message by name - // once we have built the full file descriptor, we can look up for the input message using its name - private case class NamedComponentMethod( - serviceMethod: ServiceMethod, - serializer: JsonSerializer, - grpcMethodName: String, - extractorCreators: Map[Int, ExtractorCreator], - inputMessageName: String, - inputProto: Option[DescriptorProto]) { - - type ParameterExtractorsArray = Array[ParameterExtractor[InvocationContext, AnyRef]] - - def toCommandHandler(fileDescriptor: FileDescriptor): CommandHandler = { - serviceMethod match { - case method: CommandHandlerMethod => - val messageDescriptor = fileDescriptor.findMessageTypeByName(inputMessageName) - // CommandHandler request always have proto messages as input, - // their type url are prefixed by DefaultTypeUrlPrefix - // It's possible for a user to configure another prefix, but this is done through the Kalix instance - // and the Java SDK doesn't expose it. - val typeUrl = AnySupport.DefaultTypeUrlPrefix + "/" + messageDescriptor.getFullName - val methodInvokers = - serviceMethod.javaMethodOpt - .map { meth => - val parameterExtractors: ParameterExtractorsArray = { - meth.getParameterTypes.length match { - case 1 => - Array( - new ParameterExtractors.BodyExtractor( - messageDescriptor.findFieldByNumber(1), - method.inputType, - serializer)) - case 0 => - // parameterless method, not extractor needed - Array.empty - case n => - throw new IllegalStateException( - s"Command handler ${method} is expecting $n parameters, should be 0 or 1") - } - } - Map(typeUrl -> MethodInvoker(meth, parameterExtractors)) - } - .getOrElse(Map.empty) - - CommandHandler(grpcMethodName, serializer, messageDescriptor, methodInvokers) - - case method: CombinedSubscriptionServiceMethod => - val methodInvokers = - method.methodsMap.map { case (typeUrl, meth) => - val parameterExtractors: ParameterExtractorsArray = { - meth.getParameterTypes.length match { - case 1 => - Array(new ParameterExtractors.AnyBodyExtractor[AnyRef](meth.getParameterTypes.head, serializer)) - case n => - throw new IllegalStateException( - s"Update handler ${method} is expecting $n parameters, should be 1, the update") - } - } - - (typeUrl, MethodInvoker(meth, parameterExtractors)) - } - - CommandHandler(grpcMethodName, serializer, JavaPbAny.getDescriptor, methodInvokers) - - case method: SubscriptionServiceMethod => - val methodInvokers = - serviceMethod.javaMethodOpt - .map { meth => - - val parameterExtractors: ParameterExtractorsArray = - Array(ParameterExtractors.AnyBodyExtractor(method.inputType, serializer)) - - val typeUrls = serializer.contentTypesFor(method.inputType) - typeUrls.map(_ -> MethodInvoker(meth, parameterExtractors)).toMap - } - .getOrElse(Map.empty) - - CommandHandler(grpcMethodName, serializer, JavaPbAny.getDescriptor, methodInvokers) - - case _: VirtualServiceMethod => - //java method is empty - CommandHandler(grpcMethodName, serializer, JavaPbAny.getDescriptor, Map.empty) - - case _: DeleteServiceMethod => - val methodInvokers = serviceMethod.javaMethodOpt.map { meth => - (ProtobufEmptyTypeUrl, MethodInvoker(meth, Array.empty[ParameterExtractor[InvocationContext, AnyRef]])) - }.toMap - - CommandHandler(grpcMethodName, serializer, Empty.getDescriptor, methodInvokers) - - case method: ActionHandlerMethod => - val messageDescriptor = fileDescriptor.findMessageTypeByName(inputMessageName) - // Action handler request always have proto messages as input, - // their type url are prefixed by DefaultTypeUrlPrefix - // It's possible for a user to configure another prefix, but this is done through the Kalix instance - // and the Java SDK doesn't expose it. - val typeUrl = AnySupport.DefaultTypeUrlPrefix + "/" + messageDescriptor.getFullName - val methodInvokers = - serviceMethod.javaMethodOpt - .map { meth => - val parameterExtractors: ParameterExtractorsArray = - if (meth.getParameterTypes.length == 1) - Array( - new ParameterExtractors.BodyExtractor( - messageDescriptor.findFieldByNumber(1), - method.inputType, - serializer)) - else - Array.empty // parameterless method, not extractor needed - - Map(typeUrl -> MethodInvoker(meth, parameterExtractors)) - } - .getOrElse(Map.empty) - - CommandHandler(grpcMethodName, serializer, messageDescriptor, methodInvokers) - } - - } - } - - private def buildActionHandlerMessageAndExtractors( - nameGenerator: NameGenerator, - actionHandlerMethod: ActionHandlerMethod): (DescriptorProto, Map[Int, ExtractorCreator]) = { - val inputMessageName = nameGenerator.getName(actionHandlerMethod.methodName.capitalize + "KalixSyntheticRequest") - - val inputMessageDescriptor = DescriptorProto.newBuilder() - inputMessageDescriptor.setName(inputMessageName) - - if (actionHandlerMethod.hasInputType) { - val bodyFieldDesc = FieldDescriptorProto - .newBuilder() - // todo ensure this is unique among field names - .setName("json_body") - // Always put the body at position 1 - even if there's no body, leave position 1 free. This keeps the body - // parameter stable in case the user adds a body. - .setNumber(1) - .setType(FieldDescriptorProto.Type.TYPE_MESSAGE) - .setTypeName("google.protobuf.Any") - .build() - - inputMessageDescriptor.addField(bodyFieldDesc) - } - (inputMessageDescriptor.build(), Map.empty) - } - - private def buildCommandHandlerMessageAndExtractors( - nameGenerator: NameGenerator, - commandHandlerMethod: CommandHandlerMethod): (DescriptorProto, Map[Int, ExtractorCreator]) = { - - val inputMessageName = nameGenerator.getName(commandHandlerMethod.methodName.capitalize + "KalixSyntheticRequest") - - val inputMessageDescriptor = DescriptorProto.newBuilder() - inputMessageDescriptor.setName(inputMessageName) - - if (commandHandlerMethod.hasInputType) { - val bodyFieldDesc = FieldDescriptorProto - .newBuilder() - // todo ensure this is unique among field names - .setName("json_body") - // Always put the body at position 1 - even if there's no body, leave position 1 free. This keeps the body - // parameter stable in case the user adds a body. - .setNumber(1) - .setType(FieldDescriptorProto.Type.TYPE_MESSAGE) - .setTypeName("google.protobuf.Any") - .build() - - inputMessageDescriptor.addField(bodyFieldDesc) - } - - val idFieldDesc = FieldDescriptorProto - .newBuilder() - .setName("id") - // id always go on position 2 after the body - .setNumber(2) - .setType(FieldDescriptorProto.Type.TYPE_STRING) - .setOptions { - DescriptorProtos.FieldOptions - .newBuilder() - .setExtension(kalix.Annotations.field, kalix.FieldOptions.newBuilder().setId(true).build()) - .build() - } - .build() - - inputMessageDescriptor.addField(idFieldDesc) - (inputMessageDescriptor.build(), Map.empty) - } - - private def buildHttpRule(commandHandlerMethod: CommandHandlerMethod): HttpRule.Builder = { - val httpRule = HttpRule.newBuilder() - - val componentTypeId = - if (Reflect.isView(commandHandlerMethod.component)) { - commandHandlerMethod.component.getAnnotation(classOf[ComponentId]).value() - } else if (Reflect.isAction(commandHandlerMethod.component)) { - val annotation = commandHandlerMethod.component.getAnnotation(classOf[ComponentId]) - // don't require id on actions (subscriptions etc) - if (annotation eq null) commandHandlerMethod.getClass.getName - else annotation.value() - } else { - commandHandlerMethod.component.getAnnotation(classOf[ComponentId]).value() - } - - val urlTemplate = commandHandlerMethod.urlTemplate.templateUrl(componentTypeId, commandHandlerMethod.method.getName) - if (commandHandlerMethod.hasInputType) - httpRule.setPost(urlTemplate) - else - httpRule.setGet(urlTemplate) - - } - - private def buildGrpcMethod( - grpcMethodName: String, - inputTypeName: String, - outputTypeName: String, - streamIn: Boolean, - streamOut: Boolean): MethodDescriptorProto.Builder = - MethodDescriptorProto - .newBuilder() - .setName(grpcMethodName) - .setInputType(inputTypeName) - .setClientStreaming(streamIn) - .setServerStreaming(streamOut) - .setOutputType(outputTypeName) - } private[akka] final case class ComponentDescriptor private ( diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptorFactory.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptorFactory.scala index 7cb6633e3..661d611af 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptorFactory.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/ComponentDescriptorFactory.scala @@ -20,9 +20,6 @@ import akka.javasdk.annotations.Produce.ServiceStream import akka.javasdk.annotations.Produce.ToTopic import akka.javasdk.consumer.Consumer import akka.javasdk.eventsourcedentity.EventSourcedEntity -import akka.javasdk.impl.reflection.CombinedSubscriptionServiceMethod -import akka.javasdk.impl.reflection.KalixMethod -import akka.javasdk.impl.reflection.NameGenerator import akka.javasdk.impl.reflection.Reflect import akka.javasdk.impl.serialization.JsonSerializer import akka.javasdk.keyvalueentity.KeyValueEntity @@ -32,11 +29,6 @@ import akka.javasdk.view.View import akka.javasdk.workflow.Workflow import akka.runtime.sdk.spi.ConsumerDestination import akka.runtime.sdk.spi.ConsumerSource -import kalix.DirectSource -import kalix.EventSource -import kalix.Eventing -import kalix.ServiceEventing -import kalix.ServiceOptions // TODO: abstract away spring dependency import akka.javasdk.impl.reflection.Reflect.Syntax._ @@ -68,9 +60,6 @@ private[impl] object ComponentDescriptorFactory { def eventSourcedEntitySubscription(clazz: Class[_]): Option[FromEventSourcedEntity] = clazz.getAnnotationOption[FromEventSourcedEntity] - def topicSubscription(clazz: Class[_]): Option[FromTopic] = - clazz.getAnnotationOption[FromTopic] - def hasConsumerOutput(javaMethod: Method): Boolean = { if (javaMethod.isPublic) { javaMethod.getReturnType.isAssignableFrom(classOf[Consumer.Effect]) @@ -230,73 +219,6 @@ private[impl] object ComponentDescriptorFactory { } } - def eventingInForEventSourcedEntity(clazz: Class[_]): Eventing = { - val entityType = findEventSourcedEntityType(clazz) - val eventSource = EventSource.newBuilder().setEventSourcedEntity(entityType).build() - Eventing.newBuilder().setIn(eventSource).build() - } - - def eventingInForTopic(clazz: Class[_]): Eventing = { - Eventing.newBuilder().setIn(topicEventSource(clazz)).build() - } - - def eventingInForEventSourcedEntityServiceLevel(clazz: Class[_]): Option[kalix.ServiceOptions] = { - eventSourcedEntitySubscription(clazz).map { _ => - val entityType = findEventSourcedEntityType(clazz) - val in = EventSource.newBuilder().setEventSourcedEntity(entityType) - val eventing = ServiceEventing.newBuilder().setIn(in) - kalix.ServiceOptions.newBuilder().setEventing(eventing).build() - } - } - - def eventingInForTopicServiceLevel(clazz: Class[_]): Option[kalix.ServiceOptions] = { - topicSubscription(clazz).map { ann => - val in = EventSource.newBuilder().setTopic(ann.value()).setConsumerGroup(ann.consumerGroup()) - val eventing = ServiceEventing.newBuilder().setIn(in) - kalix.ServiceOptions.newBuilder().setEventing(eventing).build() - } - } - - def topicEventSource(clazz: Class[_]): EventSource = { - val topicName = findSubscriptionTopicName(clazz) - val consumerGroup = findSubscriptionConsumerGroup(clazz) - EventSource.newBuilder().setTopic(topicName).setConsumerGroup(consumerGroup).build() - } - - def eventingInForValueEntity(clazz: Class[_], handleDeletes: Boolean): Eventing = { - val entityType = findValueEntityType(clazz) - val eventSource = EventSource - .newBuilder() - .setValueEntity(entityType) - .setHandleDeletes(handleDeletes) - .build() - Eventing.newBuilder().setIn(eventSource).build() - } - - def subscribeToEventStream(component: Class[_]): Option[kalix.ServiceOptions] = { - Option(component.getAnnotation(classOf[FromServiceStream])).map { streamAnn => - val direct = DirectSource - .newBuilder() - .setEventStreamId(streamAnn.id()) - .setService(streamAnn.service()) - - val in = EventSource - .newBuilder() - .setDirect(direct) - .setConsumerGroup(streamAnn.consumerGroup()) - - val eventing = - ServiceEventing - .newBuilder() - .setIn(in) - - kalix.ServiceOptions - .newBuilder() - .setEventing(eventing) - .build() - } - } - // TODO: add more validations here // we should let users know if components are missing required annotations, // eg: Workflow and Entities require @TypeId, View requires @Consume @@ -308,66 +230,6 @@ private[impl] object ComponentDescriptorFactory { else TimedActionDescriptorFactory } - - def combineBy( - sourceName: String, - groupedSubscriptions: Map[String, Seq[KalixMethod]], - serializer: JsonSerializer, - component: Class[_]): Seq[KalixMethod] = { - - groupedSubscriptions.collect { - case (source, kMethods) if kMethods.size > 1 => - val methodsMap = - kMethods.flatMap { k => - val methodParameterTypes = k.serviceMethod.javaMethodOpt.get.getParameterTypes - // it is safe to pick the last parameter. An action has one and View has two. In the View always the last is the event - val eventParameter = methodParameterTypes.last - - serializer.contentTypesFor(eventParameter).map(typeUrl => (typeUrl, k.serviceMethod.javaMethodOpt.get)) - }.toMap - - KalixMethod( - CombinedSubscriptionServiceMethod( - component.getName, - "KalixSyntheticMethodOn" + sourceName + escapeMethodName(source.capitalize), - methodsMap)) - .withKalixOptions(kMethods.head.methodOptions) - - case (source, kMethod +: Nil) => - //only here it makes sense to check if the input is sealed, since kMethod size is 1 - if (kMethod.serviceMethod.javaMethodOpt.exists(_.getParameterTypes.last.isSealed)) { - val javaMethod = kMethod.serviceMethod.javaMethodOpt.get - val methodsMap = javaMethod.getParameterTypes.last.getPermittedSubclasses.toList.flatMap { subClass => - serializer.contentTypesFor(subClass).map(typeUrl => (typeUrl, javaMethod)) - }.toMap - KalixMethod( - CombinedSubscriptionServiceMethod( - component.getName, - "KalixSyntheticMethodOn" + sourceName + escapeMethodName(source.capitalize), - methodsMap)) - .withKalixOptions(kMethod.methodOptions) - } else { - kMethod - } - }.toSeq - } - - private[impl] def escapeMethodName(value: String): String = { - value.replaceAll("[\\._\\-]", "") - } - - def mergeServiceOptions(allOptions: Option[kalix.ServiceOptions]*): Option[ServiceOptions] = { - val mergedOptions = - allOptions.flatten - .foldLeft(kalix.ServiceOptions.newBuilder()) { case (builder, serviceOptions) => - builder.mergeFrom(serviceOptions) - } - .build() - - // if builder produces the default one, we can returns a None - if (mergedOptions == kalix.ServiceOptions.getDefaultInstance) None - else Some(mergedOptions) - } } private[impl] trait ComponentDescriptorFactory { @@ -375,10 +237,7 @@ private[impl] trait ComponentDescriptorFactory { /** * Inspect the component class (type), validate the annotations/methods and build a component descriptor for it. */ - def buildDescriptorFor( - componentClass: Class[_], - serializer: JsonSerializer, - nameGenerator: NameGenerator): ComponentDescriptor + def buildDescriptorFor(componentClass: Class[_], serializer: JsonSerializer): ComponentDescriptor } diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/ConsumerDescriptorFactory.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/ConsumerDescriptorFactory.scala index 9ae9f2bd3..0e732cd44 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/ConsumerDescriptorFactory.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/ConsumerDescriptorFactory.scala @@ -8,7 +8,6 @@ import akka.annotation.InternalApi import akka.javasdk.impl.ComponentDescriptorFactory._ import akka.javasdk.impl.reflection.HandleDeletesServiceMethod import akka.javasdk.impl.reflection.KalixMethod -import akka.javasdk.impl.reflection.NameGenerator import akka.javasdk.impl.reflection.Reflect import akka.javasdk.impl.reflection.SubscriptionServiceMethod import akka.javasdk.impl.serialization.JsonSerializer @@ -19,10 +18,7 @@ import akka.javasdk.impl.serialization.JsonSerializer @InternalApi private[impl] object ConsumerDescriptorFactory extends ComponentDescriptorFactory { - override def buildDescriptorFor( - component: Class[_], - serializer: JsonSerializer, - nameGenerator: NameGenerator): ComponentDescriptor = { + override def buildDescriptorFor(component: Class[_], serializer: JsonSerializer): ComponentDescriptor = { import Reflect.methodOrdering diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/EntityDescriptorFactory.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/EntityDescriptorFactory.scala index 0471ab1bc..d0e170a83 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/EntityDescriptorFactory.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/EntityDescriptorFactory.scala @@ -4,19 +4,14 @@ package akka.javasdk.impl -import akka.javasdk.impl.reflection.CommandHandlerMethod -import akka.javasdk.impl.reflection.EntityUrlTemplate -import akka.javasdk.impl.reflection.KalixMethod -import akka.javasdk.impl.reflection.NameGenerator -import akka.javasdk.impl.reflection.WorkflowUrlTemplate import java.lang.reflect.Method import scala.reflect.ClassTag -import ComponentDescriptorFactory.mergeServiceOptions -import JwtDescriptorFactory.buildJWTOptions import akka.annotation.InternalApi import akka.javasdk.eventsourcedentity.EventSourcedEntity +import akka.javasdk.impl.reflection.ActionHandlerMethod +import akka.javasdk.impl.reflection.KalixMethod import akka.javasdk.impl.serialization.JsonSerializer import akka.javasdk.keyvalueentity.KeyValueEntity import akka.javasdk.workflow.Workflow @@ -27,10 +22,7 @@ import akka.javasdk.workflow.Workflow @InternalApi private[impl] object EntityDescriptorFactory extends ComponentDescriptorFactory { - override def buildDescriptorFor( - component: Class[_], - serializer: JsonSerializer, - nameGenerator: NameGenerator): ComponentDescriptor = { + override def buildDescriptorFor(component: Class[_], serializer: JsonSerializer): ComponentDescriptor = { // command handlers candidate must have 0 or 1 parameter and return the components effect type // we might later revisit this, instead of single param, we can require (State, Cmd) => Effect like in Akka @@ -41,62 +33,31 @@ private[impl] object EntityDescriptorFactory extends ComponentDescriptorFactory !method.getName.startsWith("lambda$") } - val kalixMethods = - if (classOf[EventSourcedEntity[_, _]].isAssignableFrom(component)) { - component.getDeclaredMethods.collect { - case method if isCommandHandlerCandidate[EventSourcedEntity.Effect[_]](method) => - val servMethod = CommandHandlerMethod(component, method, EntityUrlTemplate) - val readOnlyCommandHandler = method.getReturnType == classOf[EventSourcedEntity.ReadOnlyEffect[_]] - var options = buildJWTOptions(method) - if (readOnlyCommandHandler) - options = Some( - options - .map(_.toBuilder) - .getOrElse(kalix.MethodOptions.newBuilder()) - .setReadOnly(true) - .build()) - KalixMethod(servMethod, entityIds = Seq("entity-id")) - .withKalixOptions(options) - }.toSeq - - } else if (classOf[KeyValueEntity[_]].isAssignableFrom(component)) { - component.getDeclaredMethods.collect { - case method if isCommandHandlerCandidate[KeyValueEntity.Effect[_]](method) => - val servMethod = CommandHandlerMethod(component, method, EntityUrlTemplate) - KalixMethod(servMethod, entityIds = Seq("entity-id")) - .withKalixOptions(buildJWTOptions(method)) - }.toSeq - } else if (classOf[Workflow[_]].isAssignableFrom(component)) { - component.getDeclaredMethods.collect { - case method if isCommandHandlerCandidate[Workflow.Effect[_]](method) => - val servMethod = CommandHandlerMethod(component, method, WorkflowUrlTemplate) - val readOnlyCommandHandler = method.getReturnType == classOf[Workflow.ReadOnlyEffect[_]] - var options = buildJWTOptions(method) - if (readOnlyCommandHandler) - options = Some( - options - .map(_.toBuilder) - .getOrElse(kalix.MethodOptions.newBuilder()) - .setReadOnly(true) - .build()) - KalixMethod(servMethod, entityIds = Seq("entity-id")) - .withKalixOptions(options) - }.toSeq - } else { - // should never happen - throw new RuntimeException( - s"Unsupported component type: ${component.getName}. Supported types are: EventSourcedEntity, ValueEntity, Workflow") - } + val commandHandlerMethods: Seq[KalixMethod] = if (classOf[EventSourcedEntity[_, _]].isAssignableFrom(component)) { + component.getDeclaredMethods.collect { + case method if isCommandHandlerCandidate[EventSourcedEntity.Effect[_]](method) => + val servMethod = ActionHandlerMethod(component, method) + KalixMethod(servMethod, entityIds = Seq.empty) + }.toSeq + } else if (classOf[KeyValueEntity[_]].isAssignableFrom(component)) { + component.getDeclaredMethods.collect { + case method if isCommandHandlerCandidate[KeyValueEntity.Effect[_]](method) => + val servMethod = ActionHandlerMethod(component, method) + KalixMethod(servMethod, entityIds = Seq.empty) + }.toSeq + } else if (classOf[Workflow[_]].isAssignableFrom(component)) { + component.getDeclaredMethods.collect { + case method if isCommandHandlerCandidate[Workflow.Effect[_]](method) => + val servMethod = ActionHandlerMethod(component, method) + KalixMethod(servMethod, entityIds = Seq.empty) + }.toSeq + } else { + + // should never happen + throw new RuntimeException( + s"Unsupported component type: ${component.getName}. Supported types are: EventSourcedEntity, ValueEntity, Workflow") + } - val serviceName = nameGenerator.getName(component.getSimpleName) - ComponentDescriptor( - nameGenerator, - serializer, - serviceName, - serviceOptions = mergeServiceOptions( - AclDescriptorFactory.serviceLevelAclAnnotation(component, default = Some(AclDescriptorFactory.denyAll)), - JwtDescriptorFactory.serviceLevelJwtAnnotation(component)), - component.getPackageName, - kalixMethods) + ComponentDescriptor(serializer, commandHandlerMethods) } } diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/InvocationContext.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/InvocationContext.scala index 1bbf7e36c..fa1035632 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/InvocationContext.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/InvocationContext.scala @@ -58,16 +58,3 @@ class InvocationContext(val message: DynamicMessage, val metadata: Metadata) override def getAny: ScalaPbAny = ScalaPbAny.fromJavaProto(toAny(message)) } - -/** - * TODO remove me - * @param any - * @param metadata - */ -class AnyInvocationContext(val any: ScalaPbAny, metadata: Metadata) extends InvocationContext(null, metadata) { - override def getAny: ScalaPbAny = any - - override def getField(field: Descriptors.FieldDescriptor): AnyRef = ??? - - override def hasField(field: Descriptors.FieldDescriptor): Boolean = ??? -} diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/TimedActionDescriptorFactory.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/TimedActionDescriptorFactory.scala index d55d8529a..540a07885 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/TimedActionDescriptorFactory.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/TimedActionDescriptorFactory.scala @@ -4,11 +4,10 @@ package akka.javasdk.impl -import akka.javasdk.impl.reflection.ActionHandlerMethod -import akka.javasdk.impl.reflection.KalixMethod -import akka.javasdk.impl.reflection.NameGenerator import akka.annotation.InternalApi import akka.javasdk.impl.ComponentDescriptorFactory.hasTimedActionEffectOutput +import akka.javasdk.impl.reflection.ActionHandlerMethod +import akka.javasdk.impl.reflection.KalixMethod import akka.javasdk.impl.serialization.JsonSerializer /** @@ -17,10 +16,7 @@ import akka.javasdk.impl.serialization.JsonSerializer @InternalApi private[impl] object TimedActionDescriptorFactory extends ComponentDescriptorFactory { - override def buildDescriptorFor( - component: Class[_], - serializer: JsonSerializer, - nameGenerator: NameGenerator): ComponentDescriptor = { + override def buildDescriptorFor(component: Class[_], serializer: JsonSerializer): ComponentDescriptor = { val commandHandlerMethods = component.getDeclaredMethods .filter(hasTimedActionEffectOutput) diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/eventsourcedentity/ReflectiveEventSourcedEntityRouter.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/eventsourcedentity/ReflectiveEventSourcedEntityRouter.scala index 170ea5c14..b3fcb6d3a 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/eventsourcedentity/ReflectiveEventSourcedEntityRouter.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/eventsourcedentity/ReflectiveEventSourcedEntityRouter.scala @@ -7,10 +7,8 @@ package akka.javasdk.impl.eventsourcedentity import akka.annotation.InternalApi import akka.javasdk.eventsourcedentity.CommandContext import akka.javasdk.eventsourcedentity.EventSourcedEntity -import akka.javasdk.impl.AnySupport import akka.javasdk.impl.CommandHandler import akka.javasdk.impl.CommandSerialization -import akka.javasdk.impl.InvocationContext import akka.javasdk.impl.reflection.Reflect import akka.javasdk.impl.serialization.JsonSerializer import akka.runtime.sdk.spi.BytesPayload @@ -57,17 +55,9 @@ private[impl] class ReflectiveEventSourcedEntityRouter[S, E, ES <: EventSourcedE } result.asInstanceOf[EventSourcedEntity.Effect[_]] } else { - // FIXME can be proto from http-grpc-handling of the static es endpoints - val pbAnyCommand = AnySupport.toScalaPbAny(command) - val invocationContext = - InvocationContext(pbAnyCommand, commandHandler.requestMessageDescriptor, commandContext.metadata()) - - val inputTypeUrl = pbAnyCommand.typeUrl - val methodInvoker = commandHandler.getInvoker(inputTypeUrl) - - methodInvoker - .invoke(entity, invocationContext) - .asInstanceOf[EventSourcedEntity.Effect[_]] + throw new IllegalStateException( + "Could not find a matching command handler for method: " + commandName + ", content type: " + command.contentType + ", invokers keys: " + commandHandler.methodInvokers.keys + .mkString(", ")) } } diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/keyvalueentity/ReflectiveKeyValueEntityRouter.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/keyvalueentity/ReflectiveKeyValueEntityRouter.scala index 8a641b797..24a1f824c 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/keyvalueentity/ReflectiveKeyValueEntityRouter.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/keyvalueentity/ReflectiveKeyValueEntityRouter.scala @@ -5,10 +5,8 @@ package akka.javasdk.impl.keyvalueentity import akka.annotation.InternalApi -import akka.javasdk.impl.AnySupport import akka.javasdk.impl.CommandHandler import akka.javasdk.impl.CommandSerialization -import akka.javasdk.impl.InvocationContext import akka.javasdk.impl.reflection.Reflect import akka.javasdk.impl.serialization.JsonSerializer import akka.javasdk.keyvalueentity.CommandContext @@ -54,18 +52,10 @@ private[impl] class ReflectiveKeyValueEntityRouter[S, KV <: KeyValueEntity[S]]( } result.asInstanceOf[KeyValueEntity.Effect[_]] } else { - // FIXME can be proto from http-grpc-handling of the static es endpoints - val pbAnyCommand = AnySupport.toScalaPbAny(command) - val invocationContext = - InvocationContext(pbAnyCommand, commandHandler.requestMessageDescriptor, commandContext.metadata()) + throw new IllegalStateException( + "Could not find a matching command handler for method: " + commandName + ", content type: " + command.contentType + ", invokers keys: " + commandHandler.methodInvokers.keys + .mkString(", ")) - val inputTypeUrl = pbAnyCommand.typeUrl - val methodInvoker = commandHandler - .getInvoker(inputTypeUrl) - - methodInvoker - .invoke(entity, invocationContext) - .asInstanceOf[KeyValueEntity.Effect[_]] } } diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/KalixMethod.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/KalixMethod.scala index 6444f1291..f1c5514c3 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/KalixMethod.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/KalixMethod.scala @@ -49,62 +49,6 @@ private[impl] sealed trait AnyJsonRequestServiceMethod extends ServiceMethod { def inputType: Class[_] } -/** - * INTERNAL API - */ -@InternalApi -private[impl] sealed trait UrlTemplate { - def templateUrl(componentTypeId: String, methodName: String): String -} - -/** - * INTERNAL API - */ -@InternalApi -private[impl] object EntityUrlTemplate extends UrlTemplate { - override def templateUrl(componentTypeId: String, methodName: String): String = { - s"/akka/v1.0/entity/${componentTypeId}/{id}/${methodName}" - } -} - -/** - * INTERNAL API - */ -@InternalApi -private[impl] object WorkflowUrlTemplate extends UrlTemplate { - override def templateUrl(componentTypeId: String, methodName: String): String = - s"/akka/v1.0/workflow/${componentTypeId}/{id}/${methodName}" -} - -/** - * INTERNAL API - */ -@InternalApi -private[impl] object ViewUrlTemplate extends UrlTemplate { - override def templateUrl(componentTypeId: String, methodName: String): String = - s"/akka/v1.0/view/${componentTypeId}/${methodName}" -} - -/** - * Build from command handler methods on Entities and Workflows - * - * INTERNAL API - */ -@InternalApi -private[impl] final case class CommandHandlerMethod( - component: Class[_], - method: Method, - urlTemplate: UrlTemplate, - streamOut: Boolean = false) - extends AnyJsonRequestServiceMethod { - - override def methodName: String = method.getName - override def javaMethodOpt: Option[Method] = Some(method) - val hasInputType: Boolean = method.getParameterTypes.headOption.isDefined - val inputType: Class[_] = method.getParameterTypes.headOption.getOrElse(classOf[Unit]) - val streamIn: Boolean = false -} - /** * Build from command handler methods on actions * @@ -121,24 +65,6 @@ private[impl] final case class ActionHandlerMethod(component: Class[_], method: val streamOut: Boolean = false } -/** - * Build from methods annotated with @Consume at type level. - * - * It's used as a 'virtual' method because there is no Java method backing it. It will exist only in the gRPC descriptor - * and will be used for view updates with transform = false - * - * INTERNAL API - */ -@InternalApi -private[impl] final case class VirtualServiceMethod(component: Class[_], methodName: String, inputType: Class[_]) - extends AnyJsonRequestServiceMethod { - - override def javaMethodOpt: Option[Method] = None - - val streamIn: Boolean = false - val streamOut: Boolean = false -} - private[impl] final case class CombinedSubscriptionServiceMethod( componentName: String, combinedMethodName: String, @@ -197,22 +123,6 @@ private[impl] final case class HandleDeletesServiceMethod(javaMethod: Method) ex override def streamOut: Boolean = false } -/** - * Similar to VirtualServiceMethod but for deletes. - * - * INTERNAL API - */ -@InternalApi -private[impl] final case class VirtualDeleteServiceMethod(component: Class[_], methodName: String) - extends DeleteServiceMethod { - - override def javaMethodOpt: Option[Method] = None - - override def streamIn: Boolean = false - - override def streamOut: Boolean = false -} - /** * INTERNAL API */ diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/ParameterExtractor.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/ParameterExtractor.scala index 14b923246..6ca96875e 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/ParameterExtractor.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/reflection/ParameterExtractor.scala @@ -6,17 +6,13 @@ package akka.javasdk.impl.reflection import akka.annotation.InternalApi import akka.javasdk.Metadata -import akka.javasdk.impl.AnySupport -import scala.jdk.OptionConverters._ - +import akka.javasdk.impl.serialization.JsonSerializer +import akka.runtime.sdk.spi.BytesPayload import com.google.protobuf.ByteString import com.google.protobuf.Descriptors import com.google.protobuf.DynamicMessage -import com.google.protobuf.{ Any => JavaPbAny } import com.google.protobuf.any.{ Any => ScalaPbAny } -import akka.javasdk.impl.ErrorHandling.BadRequestException -import akka.javasdk.impl.serialization.JsonSerializer -import akka.runtime.sdk.spi.BytesPayload +import com.google.protobuf.{ Any => JavaPbAny } /** * Extracts method parameters from an invocation context for the purpose of passing them to a reflective invocation call @@ -65,17 +61,6 @@ private[impl] object ParameterExtractors { .build() } - private def decodeParam[T](pbAny: ScalaPbAny, cls: Class[T], serializer: JsonSerializer): T = { - if (cls == classOf[Array[Byte]]) { - val bytes = pbAny.value - AnySupport.decodePrimitiveBytes(bytes).toByteArray.asInstanceOf[T] - } else { - // FIXME we should not need these conversions - val bytesPayload = AnySupport.toSpiBytesPayload(pbAny) - serializer.fromBytes(cls, bytesPayload) - } - } - private def decodeParam[T](payload: BytesPayload, cls: Class[T], serializer: JsonSerializer): T = { if (cls == classOf[Array[Byte]]) { payload.bytes.toArrayUnsafe().asInstanceOf[T] @@ -84,16 +69,6 @@ private[impl] object ParameterExtractors { } } - private def decodeParamPossiblySealed[T](pbAny: ScalaPbAny, cls: Class[T], serializer: JsonSerializer): T = { - if (cls.isSealed) { - // FIXME we should not need these conversions - val bytesPayload = AnySupport.toSpiBytesPayload(pbAny) - serializer.fromBytes(bytesPayload).asInstanceOf[T] - } else { - decodeParam(pbAny, cls, serializer) - } - } - def decodeParamPossiblySealed[T](payload: BytesPayload, cls: Class[T], serializer: JsonSerializer): T = { if (cls.isSealed) { serializer.fromBytes(payload).asInstanceOf[T] @@ -101,63 +76,4 @@ private[impl] object ParameterExtractors { decodeParam(payload, cls, serializer) } } - - private def decodeParamCollection[T, C <: java.util.Collection[T]]( - dm: DynamicMessage, - cls: Class[T], - collectionType: Class[C], - serializer: JsonSerializer): C = { - // FIXME we should not need these conversions - val pbAny = ScalaPbAny.fromJavaProto(toAny(dm)) - val bytesPayload = AnySupport.toSpiBytesPayload(pbAny) - serializer.fromBytes(cls, collectionType, bytesPayload) - } - - case class AnyBodyExtractor[T](cls: Class[_], serializer: JsonSerializer) - extends ParameterExtractor[DynamicMessageContext, T] { - override def extract(context: DynamicMessageContext): T = - decodeParamPossiblySealed(context.getAny, cls.asInstanceOf[Class[T]], serializer) - } - - class BodyExtractor[T](field: Descriptors.FieldDescriptor, cls: Class[_], serializer: JsonSerializer) - extends ParameterExtractor[DynamicMessageContext, T] { - - override def extract(context: DynamicMessageContext): T = { - context.getField(field) match { - case dm: DynamicMessage => - decodeParam(ScalaPbAny.fromJavaProto(toAny(dm)), cls.asInstanceOf[Class[T]], serializer) - } - } - } - - class CollectionBodyExtractor[T, C <: java.util.Collection[T]]( - field: Descriptors.FieldDescriptor, - cls: Class[T], - collectionType: Class[C], - serializer: JsonSerializer) - extends ParameterExtractor[DynamicMessageContext, C] { - - override def extract(context: DynamicMessageContext): C = { - context.getField(field) match { - case dm: DynamicMessage => decodeParamCollection(dm, cls, collectionType, serializer) - } - } - } - - class FieldExtractor[T](field: Descriptors.FieldDescriptor, required: Boolean, deserialize: AnyRef => T) - extends ParameterExtractor[DynamicMessageContext, T] { - override def extract(context: DynamicMessageContext): T = { - (required, field.isRepeated || context.hasField(field)) match { - case (_, true) => deserialize(context.getField(field)) - //we know that currently this applies only to request parameters - case (true, false) => throw BadRequestException(s"Required request parameter is missing: ${field.getName}") - case (false, false) => null.asInstanceOf[T] //could be mapped to optional later on - } - } - } - - class HeaderExtractor[T >: Null](name: String, deserialize: String => T) - extends ParameterExtractor[MetadataContext, T] { - override def extract(context: MetadataContext): T = context.metadata.get(name).toScala.map(deserialize).orNull - } } diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/timedaction/TimedActionRouter.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/timedaction/TimedActionRouter.scala index eaed7b756..bbee4c563 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/timedaction/TimedActionRouter.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/timedaction/TimedActionRouter.scala @@ -57,7 +57,6 @@ abstract class TimedActionRouter[A <: TimedAction](protected val action: A) { * @return * A future of the message to return. */ - //TODO commandName rename to methodName def handleUnary(methodName: String, message: CommandEnvelope[BytesPayload]): TimedAction.Effect private def callWithContext[T](context: CommandContext)(func: () => T) = { diff --git a/akka-javasdk/src/main/scala/akka/javasdk/impl/workflow/ReflectiveWorkflowRouter.scala b/akka-javasdk/src/main/scala/akka/javasdk/impl/workflow/ReflectiveWorkflowRouter.scala index 991baaab8..d1982ce75 100644 --- a/akka-javasdk/src/main/scala/akka/javasdk/impl/workflow/ReflectiveWorkflowRouter.scala +++ b/akka-javasdk/src/main/scala/akka/javasdk/impl/workflow/ReflectiveWorkflowRouter.scala @@ -16,7 +16,6 @@ import akka.annotation.InternalApi import akka.javasdk.impl.AnySupport import akka.javasdk.impl.CommandHandler import akka.javasdk.impl.CommandSerialization -import akka.javasdk.impl.InvocationContext import akka.javasdk.impl.WorkflowExceptions.WorkflowException import akka.javasdk.impl.serialization.JsonSerializer import akka.javasdk.impl.workflow.ReflectiveWorkflowRouter.CommandHandlerNotFound @@ -115,18 +114,9 @@ class ReflectiveWorkflowRouter[S, W <: Workflow[S]]( } result.asInstanceOf[Workflow.Effect[_]] } else { - - // FIXME can be proto from http-grpc-handling of the static es endpoints - val pbAnyCommand = AnySupport.toScalaPbAny(command) - val invocationContext = - InvocationContext(pbAnyCommand, commandHandler.requestMessageDescriptor, context.metadata()) - - val inputTypeUrl = pbAnyCommand.typeUrl - - val methodInvoker = commandHandler.getInvoker(inputTypeUrl) - methodInvoker - .invoke(workflow, invocationContext) - .asInstanceOf[Workflow.Effect[_]] + throw new IllegalStateException( + "Could not find a matching command handler for method: " + commandName + ", content type: " + command.contentType + ", invokers keys: " + commandHandler.methodInvokers.keys + .mkString(", ")) } } catch { diff --git a/akka-javasdk/src/test/java/akka/javasdk/client/ComponentClientTest.java b/akka-javasdk/src/test/java/akka/javasdk/client/ComponentClientTest.java index 73851fcbb..abddd5529 100644 --- a/akka-javasdk/src/test/java/akka/javasdk/client/ComponentClientTest.java +++ b/akka-javasdk/src/test/java/akka/javasdk/client/ComponentClientTest.java @@ -124,11 +124,9 @@ public void shouldReturnDeferredCallWithTraceParent() { @Test public void shouldReturnDeferredCallForValueEntity() throws InvalidProtocolBufferException { //given - var counterVE = descriptorFor(Counter.class, serializer); - var targetMethod = counterVE.serviceDescriptor().findMethodByName("RandomIncrease"); Integer param = 10; - var id = "abc123"; + //when DeferredCallImpl call = (DeferredCallImpl) componentClient.forKeyValueEntity(id) @@ -137,7 +135,6 @@ public void shouldReturnDeferredCallForValueEntity() throws InvalidProtocolBuffe //then assertThat(call.componentId()).isEqualTo(ComponentDescriptorFactory.readComponentIdIdValue(Counter.class)); - assertThat(call.methodName()).isEqualTo(targetMethod.getName()); assertEquals(10, call.message()); } diff --git a/akka-javasdk/src/test/java/akka/javasdk/testmodels/eventsourcedentity/EventSourcedEntitiesTestModels.java b/akka-javasdk/src/test/java/akka/javasdk/testmodels/eventsourcedentity/EventSourcedEntitiesTestModels.java index abfd2fc3c..869624172 100644 --- a/akka-javasdk/src/test/java/akka/javasdk/testmodels/eventsourcedentity/EventSourcedEntitiesTestModels.java +++ b/akka-javasdk/src/test/java/akka/javasdk/testmodels/eventsourcedentity/EventSourcedEntitiesTestModels.java @@ -81,88 +81,6 @@ public Integer applyEvent(CounterEvent event) { } - - @ComponentId("counter") - public static class CounterEventSourcedEntityWithMethodLevelJWT extends EventSourcedEntity { - - @JWT( - validate = JWT.JwtMethodMode.BEARER_TOKEN, - bearerTokenIssuers = {"a", "b"}) - public ReadOnlyEffect getInteger() { - return effects().reply(currentState()); - } - - @JWT( - validate = JWT.JwtMethodMode.BEARER_TOKEN, - bearerTokenIssuers = {"c", "d"}, - staticClaims = { - @JWT.StaticClaim(claim = "role", values = "method-admin"), - @JWT.StaticClaim(claim = "aud", values = "${ENV}") - }) - public ReadOnlyEffect changeInteger(Integer number) { - return effects().reply(number); - } - - @Override - public Integer applyEvent(CounterEvent event) { - return 0; - } - } - - @ComponentId("counter") - @JWT( - validate = JWT.JwtMethodMode.BEARER_TOKEN, - bearerTokenIssuers = {"a", "b"}, - staticClaims = { - @JWT.StaticClaim(claim = "role", values = "admin"), - @JWT.StaticClaim(claim = "aud", values = "${ENV}.kalix.io") - }) - public static class CounterEventSourcedEntityWithServiceLevelJWT extends EventSourcedEntity { - - public ReadOnlyEffect getInteger() { - return effects().reply(currentState()); - } - - public ReadOnlyEffect changeInteger(Integer number) { - return effects().reply(number); - } - - @Override - public Integer applyEvent(CounterEvent event) { - return 0; - } - } - - - - @ComponentId("counter") - @Acl(allow = @Acl.Matcher(service = "test")) - public static class EventSourcedEntityWithServiceLevelAcl extends EventSourcedEntity { - - - @Override - public Employee applyEvent(EmployeeEvent event) { - return null; - } - } - - - @ComponentId("counter") - public static class EventSourcedEntityWithMethodLevelAcl extends EventSourcedEntity { - - @Acl(allow = @Acl.Matcher(service = "test")) - public Effect createUser(CreateEmployee create) { - return effects() - .persist(new EmployeeEvent.EmployeeCreated(create.firstName, create.lastName, create.email)) - .thenReply(__ -> "ok"); - } - - @Override - public Employee applyEvent(EmployeeEvent event) { - return null; - } - } - @ComponentId("counter") public static class InvalidEventSourcedEntityWithOverloadedCommandHandler extends EventSourcedEntity { diff --git a/akka-javasdk/src/test/java/akka/javasdk/testmodels/keyvalueentity/ValueEntitiesTestModels.java b/akka-javasdk/src/test/java/akka/javasdk/testmodels/keyvalueentity/ValueEntitiesTestModels.java index 70f412728..cc63aca62 100644 --- a/akka-javasdk/src/test/java/akka/javasdk/testmodels/keyvalueentity/ValueEntitiesTestModels.java +++ b/akka-javasdk/src/test/java/akka/javasdk/testmodels/keyvalueentity/ValueEntitiesTestModels.java @@ -4,56 +4,12 @@ package akka.javasdk.testmodels.keyvalueentity; -import akka.javasdk.annotations.Acl; -import akka.javasdk.annotations.JWT; import akka.javasdk.annotations.ComponentId; import akka.javasdk.keyvalueentity.KeyValueEntity; import akka.javasdk.testmodels.Done; public class ValueEntitiesTestModels { - @ComponentId("user") - @Acl(allow = @Acl.Matcher(service = "test")) - public static class ValueEntityWithServiceLevelAcl extends KeyValueEntity { - } - - @ComponentId("user") - public static class ValueEntityWithMethodLevelAcl extends KeyValueEntity { - @Acl(allow = @Acl.Matcher(service = "test")) - public KeyValueEntity.Effect createEntity(CreateUser createUser) { - return effects().reply(Done.instance); - } - } - - @JWT( - validate = JWT.JwtMethodMode.BEARER_TOKEN, - bearerTokenIssuers = {"a", "b"}, - staticClaims = { - @JWT.StaticClaim(claim = "role", values = "admin"), - @JWT.StaticClaim(claim = "aud", values = "${ENV}.kalix.io") - }) - @ComponentId("user") - public static class ValueEntityWithServiceLevelJwt extends KeyValueEntity { - public KeyValueEntity.Effect createEntity(CreateUser createUser) { - return effects().reply(Done.instance); - } - } - - @ComponentId("user") - public static class ValueEntityWithMethodLevelJwt extends KeyValueEntity { - - @JWT( - validate = JWT.JwtMethodMode.BEARER_TOKEN, - bearerTokenIssuers = {"c", "d"}, - staticClaims = { - @JWT.StaticClaim(claim = "role", values = "method-admin"), - @JWT.StaticClaim(claim = "aud", values = "${ENV}") - }) - public KeyValueEntity.Effect createEntity(CreateUser createUser) { - return effects().reply(Done.instance); - } - } - @ComponentId("user") public static class InvalidValueEntityWithOverloadedCommandHandler extends KeyValueEntity { public KeyValueEntity.Effect createEntity(CreateUser createUser) { diff --git a/akka-javasdk/src/test/scala/akka/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala b/akka-javasdk/src/test/scala/akka/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala index 0e1add07d..5920c366f 100644 --- a/akka-javasdk/src/test/scala/akka/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala +++ b/akka-javasdk/src/test/scala/akka/javasdk/impl/EventSourcedEntityDescriptorFactorySpec.scala @@ -4,16 +4,7 @@ package akka.javasdk.impl -import scala.jdk.CollectionConverters.CollectionHasAsScala - -import akka.javasdk.testmodels.eventsourcedentity.EventSourcedEntitiesTestModels.CounterEventSourcedEntity -import akka.javasdk.testmodels.eventsourcedentity.EventSourcedEntitiesTestModels.CounterEventSourcedEntityWithMethodLevelJWT -import akka.javasdk.testmodels.eventsourcedentity.EventSourcedEntitiesTestModels.CounterEventSourcedEntityWithServiceLevelJWT -import akka.javasdk.testmodels.eventsourcedentity.EventSourcedEntitiesTestModels.EventSourcedEntityWithMethodLevelAcl -import akka.javasdk.testmodels.eventsourcedentity.EventSourcedEntitiesTestModels.EventSourcedEntityWithServiceLevelAcl import akka.javasdk.testmodels.eventsourcedentity.EventSourcedEntitiesTestModels.InvalidEventSourcedEntityWithOverloadedCommandHandler -import kalix.JwtMethodOptions.JwtMethodMode -import kalix.JwtServiceOptions.JwtServiceMode import org.scalatest.wordspec.AnyWordSpec class EventSourcedEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { @@ -27,88 +18,6 @@ class EventSourcedEntityDescriptorFactorySpec extends AnyWordSpec with Component "NotPublicEventSourced is not marked with `public` modifier. Components must be public.") } - "annotate read only command handlers for the runtime" in { - assertDescriptor[CounterEventSourcedEntity] { desc => - val getIngeterOptions = findKalixMethodOptions(desc, "GetInteger") - getIngeterOptions.getReadOnly shouldEqual true - - val changeIntegerOptions = findKalixMethodOptions(desc, "ChangeInteger") - changeIntegerOptions.getReadOnly shouldEqual false - } - } - - "generate HTTP mappings for an entity" in { - assertDescriptor[CounterEventSourcedEntity] { desc => - val method = desc.commandHandlers("GetInteger") - val getIntegerUrl = findHttpRule(desc, method.grpcMethodName).getGet - getIntegerUrl shouldBe "/akka/v1.0/entity/counter-entity/{id}/getInteger" - - val postMethod = desc.commandHandlers("ChangeInteger") - val changeIntegerUrl = findHttpRule(desc, postMethod.grpcMethodName).getPost - changeIntegerUrl shouldBe "/akka/v1.0/entity/counter-entity/{id}/changeInteger" - } - } - - "generate HTTP mappings with method level JWT annotation" in { - assertDescriptor[CounterEventSourcedEntityWithMethodLevelJWT] { desc => - val method = desc.commandHandlers("GetInteger") - val getIntegerUrl = findHttpRule(desc, method.grpcMethodName).getGet - getIntegerUrl shouldBe "/akka/v1.0/entity/counter/{id}/getInteger" - - val jwtOption = findKalixMethodOptions(desc, method.grpcMethodName).getJwt - jwtOption.getBearerTokenIssuer(0) shouldBe "a" - jwtOption.getBearerTokenIssuer(1) shouldBe "b" - jwtOption.getValidate(0) shouldBe JwtMethodMode.BEARER_TOKEN - - val postMethod = desc.commandHandlers("ChangeInteger") - val changeIntegerUrl = findHttpRule(desc, postMethod.grpcMethodName).getPost - changeIntegerUrl shouldBe "/akka/v1.0/entity/counter/{id}/changeInteger" - - val jwtOption2 = findKalixMethodOptions(desc, postMethod.grpcMethodName).getJwt - jwtOption2.getBearerTokenIssuer(0) shouldBe "c" - jwtOption2.getBearerTokenIssuer(1) shouldBe "d" - jwtOption2.getValidate(0) shouldBe JwtMethodMode.BEARER_TOKEN - - val Seq(claim1, claim2) = jwtOption2.getStaticClaimList.asScala.toSeq - claim1.getClaim shouldBe "role" - claim1.getValue(0) shouldBe "method-admin" - claim2.getClaim shouldBe "aud" - claim2.getValue(0) shouldBe "${ENV}" - } - } - - "generate mappings for service level JWT annotation" in { - assertDescriptor[CounterEventSourcedEntityWithServiceLevelJWT] { desc => - val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) - val jwtOption = extension.getJwt - jwtOption.getBearerTokenIssuer(0) shouldBe "a" - jwtOption.getBearerTokenIssuer(1) shouldBe "b" - jwtOption.getValidate shouldBe JwtServiceMode.BEARER_TOKEN - - val Seq(claim1, claim2) = jwtOption.getStaticClaimList.asScala.toSeq - claim1.getClaim shouldBe "role" - claim1.getValue(0) shouldBe "admin" - claim2.getClaim shouldBe "aud" - claim2.getValue(0) shouldBe "${ENV}.kalix.io" - } - } - - "generate ACL annotations at service level" in { - assertDescriptor[EventSourcedEntityWithServiceLevelAcl] { desc => - val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) - val service = extension.getAcl.getAllow(0).getService - service shouldBe "test" - } - } - - "generate ACL annotations at method level" in { - assertDescriptor[EventSourcedEntityWithMethodLevelAcl] { desc => - val extension = findKalixMethodOptions(desc, "CreateUser") - val service = extension.getAcl.getAllow(0).getService - service shouldBe "test" - } - } - "not allow overloaded command handlers" in { intercept[ValidationException] { Validations.validate(classOf[InvalidEventSourcedEntityWithOverloadedCommandHandler]).failIfInvalid() diff --git a/akka-javasdk/src/test/scala/akka/javasdk/impl/KeyValueEntityDescriptorFactorySpec.scala b/akka-javasdk/src/test/scala/akka/javasdk/impl/KeyValueEntityDescriptorFactorySpec.scala index 6d61b4231..c8ef5eb3a 100644 --- a/akka-javasdk/src/test/scala/akka/javasdk/impl/KeyValueEntityDescriptorFactorySpec.scala +++ b/akka-javasdk/src/test/scala/akka/javasdk/impl/KeyValueEntityDescriptorFactorySpec.scala @@ -4,18 +4,7 @@ package akka.javasdk.impl -import akka.javasdk.impl.ValidationException -import akka.javasdk.impl.Validations -import akka.javasdk.testmodels.keyvalueentity.Counter - -import scala.jdk.CollectionConverters.CollectionHasAsScala -import kalix.JwtMethodOptions.JwtMethodMode -import kalix.JwtServiceOptions.JwtServiceMode import akka.javasdk.testmodels.keyvalueentity.ValueEntitiesTestModels.InvalidValueEntityWithOverloadedCommandHandler -import akka.javasdk.testmodels.keyvalueentity.ValueEntitiesTestModels.ValueEntityWithMethodLevelAcl -import akka.javasdk.testmodels.keyvalueentity.ValueEntitiesTestModels.ValueEntityWithMethodLevelJwt -import akka.javasdk.testmodels.keyvalueentity.ValueEntitiesTestModels.ValueEntityWithServiceLevelAcl -import akka.javasdk.testmodels.keyvalueentity.ValueEntitiesTestModels.ValueEntityWithServiceLevelJwt import org.scalatest.wordspec.AnyWordSpec class KeyValueEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { @@ -28,68 +17,6 @@ class KeyValueEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDesc "NotPublicValueEntity is not marked with `public` modifier. Components must be public.") } - "generate mappings for a Key Value Entity" in { - assertDescriptor[Counter] { desc => - - val increaseMethod = desc.commandHandlers("Increase") - val increaseUrl = findHttpRule(desc, increaseMethod.grpcMethodName).getPost - increaseUrl shouldBe "/akka/v1.0/entity/ve-counter/{id}/increase" - - val randomIncreaseMethod = desc.commandHandlers("RandomIncrease") - val randomIncreaseUrl = findHttpRule(desc, randomIncreaseMethod.grpcMethodName).getPost - randomIncreaseUrl shouldBe "/akka/v1.0/entity/ve-counter/{id}/randomIncrease" - - val getMethod = desc.commandHandlers("Get") - val getUrl = findHttpRule(desc, getMethod.grpcMethodName).getGet - getUrl shouldBe "/akka/v1.0/entity/ve-counter/{id}/get" - } - } - - "generate ACL annotations at service level" in { - assertDescriptor[ValueEntityWithServiceLevelAcl] { desc => - val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) - val service = extension.getAcl.getAllow(0).getService - service shouldBe "test" - } - } - - "generate ACL annotations at method level" in { - assertDescriptor[ValueEntityWithMethodLevelAcl] { desc => - val extension = findKalixMethodOptions(desc, "CreateEntity") - val service = extension.getAcl.getAllow(0).getService - service shouldBe "test" - } - } - - "generate descriptor for ValueEntity with service level JWT annotation" in { - assertDescriptor[ValueEntityWithServiceLevelJwt] { desc => - val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) - val jwtOption = extension.getJwt - jwtOption.getBearerTokenIssuer(0) shouldBe "a" - jwtOption.getBearerTokenIssuer(1) shouldBe "b" - jwtOption.getValidate shouldBe JwtServiceMode.BEARER_TOKEN - val Seq(claim1, claim2) = jwtOption.getStaticClaimList.asScala.toSeq - claim1.getClaim shouldBe "role" - claim1.getValue(0) shouldBe "admin" - claim2.getClaim shouldBe "aud" - claim2.getValue(0) shouldBe "${ENV}.kalix.io" - } - } - - "generate descriptor for ValueEntity with method level JWT annotation" in { - assertDescriptor[ValueEntityWithMethodLevelJwt] { desc => - val jwtOption = findKalixMethodOptions(desc, "CreateEntity").getJwt - jwtOption.getBearerTokenIssuer(0) shouldBe "c" - jwtOption.getBearerTokenIssuer(1) shouldBe "d" - jwtOption.getValidate(0) shouldBe JwtMethodMode.BEARER_TOKEN - val Seq(claim1, claim2) = jwtOption.getStaticClaimList.asScala.toSeq - claim1.getClaim shouldBe "role" - claim1.getValue(0) shouldBe "method-admin" - claim2.getClaim shouldBe "aud" - claim2.getValue(0) shouldBe "${ENV}" - } - } - "not allow overloaded command handlers" in { intercept[ValidationException] { Validations.validate(classOf[InvalidValueEntityWithOverloadedCommandHandler]).failIfInvalid() diff --git a/akka-javasdk/src/test/scala/akka/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala b/akka-javasdk/src/test/scala/akka/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala index 475eaa7a0..d111da611 100644 --- a/akka-javasdk/src/test/scala/akka/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala +++ b/akka-javasdk/src/test/scala/akka/javasdk/impl/WorkflowEntityDescriptorFactorySpec.scala @@ -4,18 +4,6 @@ package akka.javasdk.impl -import akka.javasdk.impl.ValidationException -import akka.javasdk.impl.Validations - -import scala.jdk.CollectionConverters.CollectionHasAsScala -import com.google.protobuf.Descriptors.FieldDescriptor.JavaType -import kalix.JwtMethodOptions.JwtMethodMode -import kalix.JwtServiceOptions.JwtServiceMode -import akka.javasdk.testmodels.workflow.WorkflowTestModels.TransferWorkflow -import akka.javasdk.testmodels.workflow.WorkflowTestModels.WorkflowWithAcl -import akka.javasdk.testmodels.workflow.WorkflowTestModels.WorkflowWithMethodLevelAcl -import akka.javasdk.testmodels.workflow.WorkflowTestModels.WorkflowWithMethodLevelJWT -import akka.javasdk.testmodels.workflow.WorkflowTestModels.WorkflowWithServiceLevelJWT import org.scalatest.wordspec.AnyWordSpec class WorkflowEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDescriptorSuite { @@ -26,76 +14,6 @@ class WorkflowEntityDescriptorFactorySpec extends AnyWordSpec with ComponentDesc Validations.validate(classOf[NotPublicComponents.NotPublicWorkflow]).failIfInvalid() }.getMessage should include("NotPublicWorkflow is not marked with `public` modifier. Components must be public.") } - - "generate mappings for a Workflow with entity ids in path" in { - assertDescriptor[TransferWorkflow] { desc => - val startTransferMethod = desc.commandHandlers("StartTransfer") - val startTransferUrl = findHttpRule(desc, startTransferMethod.grpcMethodName).getPost - startTransferUrl shouldBe "/akka/v1.0/workflow/transfer-workflow/{id}/startTransfer" - - val fieldKey = "id" - assertRequestFieldJavaType(startTransferMethod, fieldKey, JavaType.STRING) - assertEntityIdField(startTransferMethod, fieldKey) - assertRequestFieldJavaType(startTransferMethod, "json_body", JavaType.MESSAGE) - - val getStateMethod = desc.commandHandlers("GetState") - val getStateUrl = findHttpRule(desc, getStateMethod.grpcMethodName).getGet - getStateUrl shouldBe "/akka/v1.0/workflow/transfer-workflow/{id}/getState" - } - } - - "generate mappings for a Workflow with workflow keys in path and method level JWT annotation" in { - assertDescriptor[WorkflowWithMethodLevelJWT] { desc => - val method = desc.commandHandlers("StartTransfer") - val fieldKey = "id" - assertRequestFieldJavaType(method, fieldKey, JavaType.STRING) - assertEntityIdField(method, fieldKey) - assertRequestFieldJavaType(method, "json_body", JavaType.MESSAGE) - - val jwtOption = findKalixMethodOptions(desc, method.grpcMethodName).getJwt - jwtOption.getBearerTokenIssuer(0) shouldBe "a" - jwtOption.getBearerTokenIssuer(1) shouldBe "b" - jwtOption.getValidate(0) shouldBe JwtMethodMode.BEARER_TOKEN - - val Seq(claim1, claim2) = jwtOption.getStaticClaimList.asScala.toSeq - claim1.getClaim shouldBe "role" - claim1.getValue(0) shouldBe "method-admin" - claim2.getClaim shouldBe "aud" - claim2.getValue(0) shouldBe "${ENV}.kalix.io" - } - } - - "generate mappings for a Workflow with workflow keys in path and service level JWT annotation" in { - assertDescriptor[WorkflowWithServiceLevelJWT] { desc => - val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) - val jwtOption = extension.getJwt - jwtOption.getBearerTokenIssuer(0) shouldBe "c" - jwtOption.getBearerTokenIssuer(1) shouldBe "d" - jwtOption.getValidate shouldBe JwtServiceMode.BEARER_TOKEN - - val Seq(claim1, claim2) = jwtOption.getStaticClaimList.asScala.toSeq - claim1.getClaim shouldBe "role" - claim1.getValue(0) shouldBe "admin" - claim2.getClaim shouldBe "aud" - claim2.getValue(0) shouldBe "${ENV}" - } - } - - "generate ACL annotations at service level" in { - assertDescriptor[WorkflowWithAcl] { desc => - val extension = desc.serviceDescriptor.getOptions.getExtension(kalix.Annotations.service) - val service = extension.getAcl.getAllow(0).getService - service shouldBe "test" - } - } - - "generate ACL annotations at method level" in { - assertDescriptor[WorkflowWithMethodLevelAcl] { desc => - val extension = findKalixMethodOptions(desc, "StartTransfer") - val service = extension.getAcl.getAllow(0).getService - service shouldBe "test" - } - } } } diff --git a/akka-javasdk/src/test/scala/akka/javasdk/impl/reflection/KalixMethodSpec.scala b/akka-javasdk/src/test/scala/akka/javasdk/impl/reflection/KalixMethodSpec.scala deleted file mode 100644 index e8a8d098f..000000000 --- a/akka-javasdk/src/test/scala/akka/javasdk/impl/reflection/KalixMethodSpec.scala +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2021-2024 Lightbend Inc. - */ - -package akka.javasdk.impl.reflection - -import akka.javasdk.impl.reflection.KalixMethod -import akka.javasdk.impl.reflection.VirtualServiceMethod -import org.scalatest.matchers.should.Matchers -import org.scalatest.wordspec.AnyWordSpec - -class KalixMethodSpec extends AnyWordSpec with Matchers { - - "A KalixMethod" should { - "merge eventing out with in doesn't remove in" in { - val eventingWithIn = kalix.Eventing.newBuilder().setIn(kalix.EventSource.newBuilder().setTopic("a")) - val eventingWithOut = kalix.Eventing.newBuilder().setOut(kalix.EventDestination.newBuilder().setTopic("b")) - - val original = kalix.MethodOptions.newBuilder().setEventing(eventingWithIn) - val addOn = kalix.MethodOptions.newBuilder().setEventing(eventingWithOut) - val kalixMethod = KalixMethod(VirtualServiceMethod(classOf[Integer], "", classOf[Integer])) - .mergeKalixOptions(Some(original.build()), addOn.build()) - - kalixMethod.getEventing.getIn.getTopic shouldBe "a" - kalixMethod.getEventing.getOut.getTopic shouldBe "b" - } - } -} diff --git a/akka-javasdk/src/test/scala/akka/javasdk/impl/timedaction/TimedActionImplSpec.scala b/akka-javasdk/src/test/scala/akka/javasdk/impl/timedaction/TimedActionImplSpec.scala index e82bc1143..18e7565e8 100644 --- a/akka-javasdk/src/test/scala/akka/javasdk/impl/timedaction/TimedActionImplSpec.scala +++ b/akka-javasdk/src/test/scala/akka/javasdk/impl/timedaction/TimedActionImplSpec.scala @@ -79,7 +79,7 @@ class TimedActionImplSpec "The action service" should { "invoke command handler" in { - val service = create(TimedActionDescriptorFactory.buildDescriptorFor(classOf[TestTimedAction], serializer, null)) + val service = create(TimedActionDescriptorFactory.buildDescriptorFor(classOf[TestTimedAction], serializer)) val reply: SpiTimedAction.Effect = service @@ -91,7 +91,7 @@ class TimedActionImplSpec } "turn thrown command handler exceptions into failure responses" in { - val service = create(TimedActionDescriptorFactory.buildDescriptorFor(classOf[TestTimedAction], serializer, null)) + val service = create(TimedActionDescriptorFactory.buildDescriptorFor(classOf[TestTimedAction], serializer)) val reply = LoggingTestKit