From d9d0b786040df8632ed2d8ad75f5dd9b7f6640af Mon Sep 17 00:00:00 2001 From: Renato Cavalcanti Date: Tue, 28 Nov 2023 16:02:02 +0100 Subject: [PATCH] feat: allow Config injection (#1886) * feat: allow Config injection * remove Config wiring to wiredInstance * fixed workflow badwiring test --- .../src/main/scala/kalix/RunMojo.scala | 36 ++++++++----------- .../scala/kalix/javasdk/KalixRunner.scala | 14 +++++--- .../spring/impl/KalixSpringApplication.scala | 20 ++++++++--- .../workflow/IllDefinedWorkflow.java | 4 +++ .../kalix/spring/badwiring/workflow/Main.java | 2 +- .../impl/KalixSpringApplicationSpec.scala | 11 ++++++ 6 files changed, 57 insertions(+), 30 deletions(-) diff --git a/maven-java/kalix-maven-plugin/src/main/scala/kalix/RunMojo.scala b/maven-java/kalix-maven-plugin/src/main/scala/kalix/RunMojo.scala index 3414cfa94c..b24ea0eebb 100644 --- a/maven-java/kalix-maven-plugin/src/main/scala/kalix/RunMojo.scala +++ b/maven-java/kalix-maven-plugin/src/main/scala/kalix/RunMojo.scala @@ -29,29 +29,30 @@ object RunMojo { log.warn("--------------------------------------------------------------------------------------") } - if (jvmArgs.nonEmpty){ + if (jvmArgs.nonEmpty) { log.info("Additional JVM arguments detected: " + jvmArgs.toSeq.mkString(", ")) } /* - * Collect any sys property starting with `kalix` and rebuild a -D property for each of them - * so we can pass it further to the forked process. + * Lookup for arguments passed to maven using -Dkey=value and rebuild a -D property for each of them. */ - def collectKalixSysProperties: Seq[String] = { - sys.props.collect { - case (key, value) if key.startsWith("kalix") => s"-D$key=$value" - }.toSeq - } + def collectSysProperties: Seq[String] = + sys.env + .get("MAVEN_CMD_LINE_ARGS") + .map { args => + args.split("\\s+").toSeq.collect { + case arg if arg.startsWith("-D") => arg + } + } + .getOrElse(Seq.empty) val mainArgs = Seq( element(name("argument"), "-classpath"), element(name("classpath"))) - - - val kalixSysProps = - collectKalixSysProperties.map { arg => + val sysProps = + collectSysProperties.map { arg => element(name("argument"), arg) } @@ -63,7 +64,7 @@ object RunMojo { val additionalJvmArgs = jvmArgs.filter(_.trim.nonEmpty).map(element(name("argument"), _)).toSeq val allArgs = - mainArgs ++ kalixSysProps ++ additionalJvmArgs ++ dockerConfig :+ + mainArgs ++ sysProps ++ additionalJvmArgs ++ dockerConfig :+ element(name("argument"), mainClass) // mainClass must be last arg executeMojo( @@ -95,14 +96,7 @@ object RunMojo { class RunMojo extends RunParameters { override def execute(): Unit = { - RunMojo( - jvmArgs, - mainClass, - getLog, - mavenProject, - mavenSession, - pluginManager, - runningSolo = true) + RunMojo(jvmArgs, mainClass, getLog, mavenProject, mavenSession, pluginManager, runningSolo = true) } } diff --git a/sdk/java-sdk-protobuf/src/main/scala/kalix/javasdk/KalixRunner.scala b/sdk/java-sdk-protobuf/src/main/scala/kalix/javasdk/KalixRunner.scala index d339c54306..d8fe2a7e14 100644 --- a/sdk/java-sdk-protobuf/src/main/scala/kalix/javasdk/KalixRunner.scala +++ b/sdk/java-sdk-protobuf/src/main/scala/kalix/javasdk/KalixRunner.scala @@ -95,7 +95,7 @@ object KalixRunner { DevModeSettings.addDevModeConfig(mainConfig) } - private def loadConfig(): Config = prepareConfig(ConfigFactory.load()) + private def loadPreparedConfig(): Config = prepareConfig(ConfigFactory.load()) } @@ -116,8 +116,10 @@ final class KalixRunner private[javasdk] ( private val dockerComposeUtils = DockerComposeUtils.fromConfig(_system.settings.config) + // The effective Akka Config instance as it maybe be tweaked for dev-mode (see KalixRunner.prepareConfig) + private[kalix] val finalConfig: Config = system.settings.config private[kalix] final val configuration = - new KalixRunner.Configuration(system.settings.config.getConfig("kalix")) + new KalixRunner.Configuration(finalConfig.getConfig("kalix")) private val services = serviceFactories.toSeq.map { case (serviceName, factory) => serviceName -> factory(system) @@ -127,14 +129,18 @@ final class KalixRunner private[javasdk] ( * Creates a KalixRunner from the given services. Use the default config to create the internal ActorSystem. */ def this(services: java.util.Map[String, java.util.function.Function[ActorSystem, Service]], sdkName: String) = { - this(ActorSystem("kalix", KalixRunner.loadConfig()), services.asScala.toMap, aclDescriptor = None, sdkName) + this(ActorSystem("kalix", KalixRunner.loadPreparedConfig()), services.asScala.toMap, aclDescriptor = None, sdkName) } def this( services: java.util.Map[String, java.util.function.Function[ActorSystem, Service]], aclDescriptor: Option[FileDescriptorProto], sdkName: String) = - this(ActorSystem("kalix", KalixRunner.loadConfig()), services.asScala.toMap, aclDescriptor = aclDescriptor, sdkName) + this( + ActorSystem("kalix", KalixRunner.loadPreparedConfig()), + services.asScala.toMap, + aclDescriptor = aclDescriptor, + sdkName) /** * Creates a KalixRunner from the given services and config. The config should have the same structure as the diff --git a/sdk/java-sdk-spring/src/main/scala/kalix/spring/impl/KalixSpringApplication.scala b/sdk/java-sdk-spring/src/main/scala/kalix/spring/impl/KalixSpringApplication.scala index f830401b7b..e4be34e1a4 100644 --- a/sdk/java-sdk-spring/src/main/scala/kalix/spring/impl/KalixSpringApplication.scala +++ b/sdk/java-sdk-spring/src/main/scala/kalix/spring/impl/KalixSpringApplication.scala @@ -339,6 +339,7 @@ case class KalixSpringApplication(applicationContext: ApplicationContext, config // last case is a catch all that lookups in the applicationContext val totalWireFunction: PartialFunction[Class[_], Any] = partial.orElse { + case p if p == classOf[Config] => kalixRunner.finalConfig // block wiring of clients into anything that is not an Action or Workflow // NOTE: if they are allowed, 'partial' should already have a matching case for them case p if p == classOf[KalixClient] => @@ -424,19 +425,28 @@ case class KalixSpringApplication(applicationContext: ApplicationContext, config ReflectiveEventSourcedEntityProvider.of( clz, messageCodec, - context => wiredInstance(clz) { case p if p == classOf[EventSourcedEntityContext] => context }) + context => + wiredInstance(clz) { + case p if p == classOf[EventSourcedEntityContext] => context + }) private def valueEntityProvider[S, VE <: ValueEntity[S]](clz: Class[VE]): ValueEntityProvider[S, VE] = ReflectiveValueEntityProvider.of( clz, messageCodec, - context => wiredInstance(clz) { case p if p == classOf[ValueEntityContext] => context }) + context => + wiredInstance(clz) { + case p if p == classOf[ValueEntityContext] => context + }) private def viewProvider[S, V <: View[S]](clz: Class[V]): ViewProvider = ReflectiveViewProvider.of[S, V]( clz, messageCodec, - context => wiredInstance(clz) { case p if p == classOf[ViewCreationContext] => context }) + context => + wiredInstance(clz) { + case p if p == classOf[ViewCreationContext] => context + }) private def multiTableViewProvider[V](clz: Class[V]): ViewProvider = ReflectiveMultiTableViewProvider.of[V]( @@ -444,6 +454,8 @@ case class KalixSpringApplication(applicationContext: ApplicationContext, config messageCodec, (viewTableClass, context) => { val constructor = viewTableClass.getConstructors.head.asInstanceOf[Constructor[View[_]]] - wiredInstance(constructor) { case p if p == classOf[ViewCreationContext] => context } + wiredInstance(constructor) { + case p if p == classOf[ViewCreationContext] => context + } }) } diff --git a/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/IllDefinedWorkflow.java b/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/IllDefinedWorkflow.java index d643b53d75..de0fb74dcf 100644 --- a/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/IllDefinedWorkflow.java +++ b/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/IllDefinedWorkflow.java @@ -16,9 +16,13 @@ package kalix.spring.badwiring.workflow; +import kalix.javasdk.annotations.Id; +import kalix.javasdk.annotations.TypeId; import kalix.javasdk.workflow.Workflow; import org.springframework.stereotype.Component; +@Id("id") +@TypeId("test") @Component public class IllDefinedWorkflow extends Workflow { @Override diff --git a/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/Main.java b/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/Main.java index ae2fa7b03b..8e02a734a0 100644 --- a/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/Main.java +++ b/sdk/java-sdk-spring/src/test/java/kalix/spring/badwiring/workflow/Main.java @@ -31,6 +31,6 @@ public class Main { public static void main(String[] args) { logger.info("Starting Kalix Application"); - SpringApplication.run(kalix.spring.badwiring.view.Main.class, args); + SpringApplication.run(Main.class, args); } } diff --git a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/KalixSpringApplicationSpec.scala b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/KalixSpringApplicationSpec.scala index d05bf9772a..f92831ed68 100644 --- a/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/KalixSpringApplicationSpec.scala +++ b/sdk/java-sdk-spring/src/test/scala/kalix/javasdk/impl/KalixSpringApplicationSpec.scala @@ -26,6 +26,8 @@ import kalix.spring.badwiring.valueentity import kalix.spring.badwiring.valueentity.IllDefinedValueEntity import kalix.spring.badwiring.view import kalix.spring.badwiring.view.IllDefinedView +import kalix.spring.badwiring.workflow +import kalix.spring.badwiring.workflow.IllDefinedWorkflow import kalix.spring.boot.KalixConfiguration import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec @@ -82,6 +84,15 @@ class KalixSpringApplicationSpec extends AnyWordSpec with Matchers { errorMessage shouldBe KalixConfiguration.beanPostProcessorErrorMessage(classOf[IllDefinedView]) } + + "block direct wiring of Kalix Workflows" in { + val errorMessage = + intercept[BeanCreationException] { + tryCatch(() => workflow.Main.main(Array.empty)) + }.getCause.getMessage + + errorMessage shouldBe KalixConfiguration.beanPostProcessorErrorMessage(classOf[IllDefinedWorkflow]) + } } }