From 51e5b395731a4339112aaa46e39e70ea326bfffe Mon Sep 17 00:00:00 2001 From: Helber Belmiro Date: Thu, 6 Jul 2023 10:04:37 -0300 Subject: [PATCH] KOGITO-9415 Francisco's review Signed-off-by: Helber Belmiro --- .../livereload/CodeGenerationResult.java | 41 ----- .../livereload/LiveReloadProcessor.java | 36 +++-- .../LiveReloadableCodeGenProvider.java | 6 + .../LiveReloadableCodeGenProviderBase.java | 9 ++ .../pom.xml | 48 ++++++ .../deployment/livereload/GreeterService.java | 151 ++++++++++++++++++ .../src/main/proto/greeting.proto | 26 +++ .../livereload/LiveReloadProcessorTest.java | 67 +++++++- .../src/test/resources/rpcgreet.sw.json | 33 ++++ 9 files changed, 363 insertions(+), 54 deletions(-) delete mode 100644 quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/CodeGenerationResult.java create mode 100644 quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/GreeterService.java create mode 100644 quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/proto/greeting.proto create mode 100644 quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/resources/rpcgreet.sw.json diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/CodeGenerationResult.java b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/CodeGenerationResult.java deleted file mode 100644 index 46c62f848bd..00000000000 --- a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/CodeGenerationResult.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2023 Red Hat, Inc. and/or its affiliates. - * - * 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 org.kie.kogito.quarkus.serverless.workflow.deployment.livereload; - -import java.util.Collection; - -import org.drools.codegen.common.GeneratedFile; -import org.jboss.jandex.IndexView; - -final class CodeGenerationResult { - - private final Collection generatedFiles; - - private final IndexView indexView; - - CodeGenerationResult(Collection generatedFiles, IndexView indexView) { - this.generatedFiles = generatedFiles; - this.indexView = indexView; - } - - Collection getGeneratedFiles() { - return generatedFiles; - } - - IndexView getIndexView() { - return indexView; - } -} diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessor.java b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessor.java index 15505039be4..398cb4257e8 100644 --- a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessor.java +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessor.java @@ -31,6 +31,7 @@ import org.drools.codegen.common.GeneratedFile; import org.drools.codegen.common.GeneratedFileType; import org.drools.drl.quarkus.util.deployment.DroolsQuarkusResourceUtils; +import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; import org.jboss.jandex.IndexView; import org.jboss.jandex.Indexer; @@ -115,12 +116,8 @@ public LiveReloadExecutionBuildItem liveReload(BuildProducer generatedFiles = new ArrayList<>(generateSources(codeGenProvider)); - if (!generatedFiles.isEmpty()) { - Collection generatedBeanBuildItems = compileGeneratedSources(generatedFiles); - return new CodeGenerationResult(generatedFiles, indexCompiledSources(generatedBeanBuildItems)); - } else { - return new CodeGenerationResult(List.of(), computingIndex); - } + return !generatedFiles.isEmpty() ? new CodeGenerationResult(generatedFiles, indexCompiledSources(compileGeneratedSources(generatedFiles))) + : new CodeGenerationResult(List.of(), computingIndex); } catch (CodeGenException e) { throw new IllegalStateException(e); } catch (IOException e) { @@ -155,11 +152,12 @@ private Collection compileGeneratedSources(Collection generateSources(LiveReloadableCodeGenProvider codeGenProvider) throws CodeGenException, IOException { Path outDir = workDir.resolve("generated-sources").resolve(codeGenProvider.providerId()); - var generatedFiles = new ArrayList(); + Collection generatedFiles = new ArrayList<>(); + Config config = ConfigProvider.getConfig(); for (Path sourcePath : kogitoBuildContext.getAppPaths().getSourcePaths()) { Path inputDir = sourcePath.resolve("main").resolve(codeGenProvider.inputDirectory()); - var codeGenContext = new CodeGenContext(applicationModel, outDir, workDir, inputDir, false, ConfigProvider.getConfig(), false); - if (codeGenProvider.trigger(codeGenContext)) { + CodeGenContext codeGenContext = new CodeGenContext(applicationModel, outDir, workDir, inputDir, false, config, false); + if (codeGenProvider.shouldRun(inputDir, config) && codeGenProvider.trigger(codeGenContext)) { try (Stream sources = Files.walk(outDir)) { sources.filter(Files::isRegularFile) .filter(path -> path.toString().endsWith(".java")) @@ -197,4 +195,24 @@ private boolean shouldSkipLiveReload() { public LiveReloadExecutionBuildItem executeWhenNotDevelopment() { return new LiveReloadExecutionBuildItem(computingIndex); } + + private static class CodeGenerationResult { + + private final Collection generatedFiles; + + private final IndexView indexView; + + CodeGenerationResult(Collection generatedFiles, IndexView indexView) { + this.generatedFiles = generatedFiles; + this.indexView = indexView; + } + + Collection getGeneratedFiles() { + return generatedFiles; + } + + IndexView getIndexView() { + return indexView; + } + } } diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProvider.java b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProvider.java index 1718e3a564e..0d02db06c33 100644 --- a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProvider.java +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProvider.java @@ -15,6 +15,10 @@ */ package org.kie.kogito.quarkus.serverless.workflow.deployment.livereload; +import java.nio.file.Path; + +import org.eclipse.microprofile.config.Config; + import io.quarkus.bootstrap.prebuild.CodeGenException; import io.quarkus.deployment.CodeGenContext; @@ -28,4 +32,6 @@ interface LiveReloadableCodeGenProvider { String providerId(); String inputDirectory(); + + boolean shouldRun(Path sourceDir, Config config); } diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProviderBase.java b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProviderBase.java index dbfeeb22f5a..a421ded7d7c 100644 --- a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProviderBase.java +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-deployment/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadableCodeGenProviderBase.java @@ -15,6 +15,10 @@ */ package org.kie.kogito.quarkus.serverless.workflow.deployment.livereload; +import java.nio.file.Path; + +import org.eclipse.microprofile.config.Config; + import io.quarkus.bootstrap.prebuild.CodeGenException; import io.quarkus.deployment.CodeGenContext; import io.quarkus.deployment.CodeGenProvider; @@ -41,4 +45,9 @@ public String inputDirectory() { public String providerId() { return delegate.providerId(); } + + @Override + public boolean shouldRun(Path sourceDir, Config config) { + return delegate.shouldRun(sourceDir, config); + } } diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/pom.xml b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/pom.xml index 504baf1b5f6..7e7787291e6 100644 --- a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/pom.xml +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/pom.xml @@ -26,6 +26,35 @@ quarkus-resteasy-jackson + + io.grpc + grpc-netty-shaded + ${version.io.grpc} + runtime + + + io.grpc + grpc-protobuf + ${version.io.grpc} + + + io.grpc + grpc-stub + ${version.io.grpc} + + + + org.apache.tomcat + annotations-api + 6.0.53 + provided + + + + io.quarkus + quarkus-junit5 + test + io.quarkus quarkus-junit5-internal @@ -36,6 +65,11 @@ rest-assured test + + org.kie.kogito + kogito-test-utils + test + @@ -79,6 +113,20 @@ + + + ${project.basedir}/src/main/proto + + greeting.proto + + + + ${project.basedir}/src/main/resources + + + + + \ No newline at end of file diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/GreeterService.java b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/GreeterService.java new file mode 100644 index 00000000000..f1b1f8ec134 --- /dev/null +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/GreeterService.java @@ -0,0 +1,151 @@ +/* + * Copyright 2023 Red Hat, Inc. and/or its affiliates. + * + * 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 org.kie.kogito.quarkus.serverless.workflow.deployment.livereload; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.kie.kogito.examples.sw.greeting.GreeterGrpc; +import org.kie.kogito.examples.sw.greeting.Greeting; +import org.kie.kogito.examples.sw.greeting.Greeting.HelloReply; +import org.kie.kogito.examples.sw.greeting.Greeting.HelloRequest; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.Status; +import io.grpc.stub.StreamObserver; +import io.quarkus.grpc.GrpcService; + +@GrpcService +public class GreeterService extends GreeterGrpc.GreeterImplBase { + + public static final String[] SUPPORTED_LANGUAGES = { "English", "Spanish" }; + + public static void main(String[] args) throws IOException, InterruptedException { + Server server = buildServer(Integer.getInteger("grpc.port", 50051)); + server.start(); + server.awaitTermination(); + } + + public static Server buildServer(int port) { + return ServerBuilder.forPort(port).addService(new GreeterService()).build(); + } + + @Override + public void sayHello(Greeting.HelloRequest request, + StreamObserver responseObserver) { + responseObserver.onNext(HelloReply.newBuilder().setMessage(getMessage(request)).build()); + responseObserver.onCompleted(); + } + + @Override + public void sayHelloAllLanguages(HelloRequest request, StreamObserver responseObserver) { + for (String language : SUPPORTED_LANGUAGES) { + HelloRequest languageRequest = HelloRequest.newBuilder(request).setLanguage(language).build(); + responseObserver.onNext(HelloReply.newBuilder().setMessage(getMessage(languageRequest)).build()); + } + responseObserver.onCompleted(); + } + + @Override + public StreamObserver sayHelloMultipleLanguagesAtOnce(StreamObserver responseObserver) { + return new StreamObserver<>() { + + private final List messages = new ArrayList<>(); + + @Override + public void onNext(HelloRequest helloRequest) { + messages.add(getMessage(helloRequest)); + } + + @Override + public void onError(Throwable throwable) { + // ignore + } + + @Override + public void onCompleted() { + responseObserver.onNext(HelloReply.newBuilder().setMessage(String.join("\n", messages)).build()); + responseObserver.onCompleted(); + } + }; + } + + @Override + public StreamObserver sayHelloMultipleLanguages(StreamObserver responseObserver) { + return new StreamObserver<>() { + @Override + public void onNext(HelloRequest helloRequest) { + responseObserver.onNext(HelloReply.newBuilder().setMessage(getMessage(helloRequest)).build()); + } + + @Override + public void onError(Throwable throwable) { + // ignore + } + + @Override + public void onCompleted() { + responseObserver.onCompleted(); + } + }; + } + + @Override + public StreamObserver sayHelloMultipleLanguagesError(StreamObserver responseObserver) { + return new StreamObserver<>() { + int counter; + + @Override + public void onNext(HelloRequest helloRequest) { + counter++; + if (counter == 2) { + responseObserver.onNext(HelloReply.newBuilder().setMessage(getMessage(helloRequest)).build()); + RuntimeException ex = Status.OUT_OF_RANGE.asRuntimeException(); + responseObserver.onError(ex); + } else if (counter < 2) { + responseObserver.onNext(HelloReply.newBuilder().setMessage(getMessage(helloRequest)).build()); + } + } + + @Override + public void onError(Throwable throwable) { + // ignore + } + + @Override + public void onCompleted() { + if (counter < 2) { + responseObserver.onCompleted(); + } + } + }; + } + + private static String getMessage(HelloRequest request) { + String message; + switch (request.getLanguage().toLowerCase()) { + case "spanish": + message = "Saludos desde gRPC service " + request.getName(); + break; + case "english": + default: + message = "Hello from gRPC service " + request.getName(); + } + return message; + } +} diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/proto/greeting.proto b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/proto/greeting.proto new file mode 100644 index 00000000000..2b47b91d7ce --- /dev/null +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/main/proto/greeting.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +option java_package="org.kie.kogito.examples.sw.greeting"; + + + +// The greeter service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} + rpc SayHelloAllLanguages (HelloRequest) returns (stream HelloReply) {} + rpc SayHelloMultipleLanguagesAtOnce (stream HelloRequest) returns (HelloReply) {} + rpc SayHelloMultipleLanguages (stream HelloRequest) returns (stream HelloReply) {} + rpc SayHelloMultipleLanguagesError (stream HelloRequest) returns (stream HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; + string language=2; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} \ No newline at end of file diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessorTest.java b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessorTest.java index e42e4cac9ca..83736311450 100644 --- a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessorTest.java +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/java/org/kie/kogito/quarkus/serverless/workflow/deployment/livereload/LiveReloadProcessorTest.java @@ -17,26 +17,52 @@ import java.io.FileInputStream; import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import org.jboss.shrinkwrap.api.ShrinkWrap; -import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.api.asset.StringAsset; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import org.kie.kogito.test.utils.SocketUtils; +import io.grpc.Server; import io.quarkus.test.QuarkusDevModeTest; +import io.restassured.RestAssured; import io.restassured.http.ContentType; import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.containsString; public class LiveReloadProcessorTest { + private static final int PORT = SocketUtils.findAvailablePort(); + @RegisterExtension public final static QuarkusDevModeTest test = new QuarkusDevModeTest() - .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)); + .withApplicationRoot(jar -> { + try { + jar.addAsResource(new StringAsset(applicationProperties()), "/application.properties"); + jar.add(new StringAsset(new String(Files.readAllBytes(Path.of("src/main/proto/greeting.proto")))), "src/main/proto/greeting.proto"); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + + private static String applicationProperties() { + return Stream.of( + "quarkus.grpc.clients.Greeter.host=localhost", + "quarkus.grpc.clients.Greeter.port=" + PORT, + "quarkus.grpc.server.port=" + PORT, + "quarkus.grpc.server.test-port=" + PORT) + .collect(Collectors.joining(System.lineSeparator())); + } @Test - void testNewWorkflow() throws IOException { + void testOpenApi() throws IOException { given() .contentType(ContentType.JSON) .accept("*/*") @@ -58,4 +84,37 @@ void testNewWorkflow() throws IOException { .statusCode(201); } + + @Test + void testEnglish() throws InterruptedException, IOException { + Server server = GreeterService.buildServer(PORT); + server.start(); + RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); + + try { + given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .body("{\"name\" : \"John\", \"language\":\"English\"}").when() + .post("/jsongreet") + .then() + .statusCode(404); + + try (FileInputStream inputStream = new FileInputStream("src/test/resources/rpcgreet.sw.json")) { + test.addResourceFile("rpcgreet.sw.json", new String(Objects.requireNonNull(inputStream).readAllBytes())); + } + + given() + .contentType(ContentType.JSON) + .accept(ContentType.JSON) + .body("{\"name\" : \"John\", \"language\":\"English\"}").when() + .post("/jsongreet") + .then() + .statusCode(201) + .body("workflowdata.message", containsString("Hello")); + } finally { + server.shutdownNow(); + server.awaitTermination(); + } + } } diff --git a/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/resources/rpcgreet.sw.json b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/resources/rpcgreet.sw.json new file mode 100644 index 00000000000..502ff1b6fa9 --- /dev/null +++ b/quarkus/extensions/kogito-quarkus-serverless-workflow-extension/kogito-quarkus-serverless-workflow-extension-live-reload-test/src/test/resources/rpcgreet.sw.json @@ -0,0 +1,33 @@ +{ + "id": "jsongreet", + "version": "1.0", + "name": "gRPC Greeting workflow", + "description": "JSON based greeting workflow using gRPC", + "start": "GreetPerson", + "functions": [ + { + "name": "sayHello", + "type": "rpc", + "operation": "greeting.proto#Greeter#SayHello" + } + ], + "states": [ + { + "name": "GreetPerson", + "type": "operation", + "actions": [ + { + "name": "sayHello", + "functionRef" : { + "refName": "sayHello", + "arguments": { + "name": ".name", + "language": ".language" + } + } + } + ], + "end": true + } + ] +}