This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push: new 6e96ceb6a9 Introduce custom CodeGenProvider for gRPC extension 6e96ceb6a9 is described below commit 6e96ceb6a9dec6d46e7c3fb6ff9743edc3033149 Author: James Netherton <jamesnether...@gmail.com> AuthorDate: Tue Aug 15 08:44:10 2023 +0100 Introduce custom CodeGenProvider for gRPC extension Co-authored-by: Peter Palaga <ppal...@redhat.com> --- docs/antora.yml | 2 - .../ROOT/pages/reference/extensions/grpc.adoc | 141 ++++--- extensions/grpc/codegen/pom.xml | 150 +++++++ .../codegen/CamelQuarkusGrpcCodegenProvider.java | 434 +++++++++++++++++++++ .../codegen/CamelQuarkusGrpcPostProcessor.java | 90 +++++ .../services/io.quarkus.deployment.CodeGenProvider | 1 + extensions/grpc/deployment/pom.xml | 4 + extensions/grpc/pom.xml | 1 + extensions/grpc/runtime/src/main/doc/usage.adoc | 86 ++-- .../quarkus/grpc/runtime/GrpcBuildTimeConfig.java | 86 ++++ integration-tests-support/grpc/pom.xml | 31 ++ .../main/resources/org/acme/proto/a/proto-a.proto | 35 ++ .../main/resources/org/acme/proto/b/proto-b.proto | 35 ++ .../resources/org/acme/proto/c/proto-c-1.proto | 35 ++ .../org/acme/proto/c/sub/package/proto-c-3.proto | 35 ++ .../resources/org/acme/proto/c/sub/proto-c-2.proto | 35 ++ .../resources/org/acme/proto/d/proto-d-1.proto | 35 ++ .../org/acme/proto/d/sub/package/proto-d-3.proto | 35 ++ .../resources/org/acme/proto/d/sub/proto-d-2.proto | 35 ++ .../main/resources/org/acme/proto/e/common.proto | 35 ++ .../main/resources/org/acme/proto/e/proto-e.proto | 19 + integration-tests-support/pom.xml | 1 + integration-tests/grpc/pom.xml | 119 +----- .../grpc/src/main/proto/pingpong.proto | 3 + .../grpc/src/main/resources/application.properties | 8 + .../camel/quarkus/component/grpc/it/GrpcTest.java | 36 ++ pom.xml | 2 - poms/bom-test/pom.xml | 5 + poms/bom/pom.xml | 5 + poms/bom/src/main/generated/flattened-full-pom.xml | 5 + .../src/main/generated/flattened-reduced-pom.xml | 5 + .../generated/flattened-reduced-verbose-pom.xml | 5 + poms/build-parent/pom.xml | 10 - 33 files changed, 1355 insertions(+), 209 deletions(-) diff --git a/docs/antora.yml b/docs/antora.yml index 365263e3d5..a7659e3b01 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -36,8 +36,6 @@ asciidoc: mapstruct-version: 1.5.5.Final # replace ${mapstruct.version} min-maven-version: 3.8.2 # replace ${min-maven-version} target-maven-version: 3.9.3 # replace ${target-maven-version} - protobuf-maven-plugin-version: 0.6.1 # replace ${protobuf-maven-plugin-version} - os-maven-plugin-version: 1.7.1 # replace ${os-maven-plugin-version} # Attributes used in xrefs to other Antora components cq-camel-components: components diff --git a/docs/modules/ROOT/pages/reference/extensions/grpc.adoc b/docs/modules/ROOT/pages/reference/extensions/grpc.adoc index 623c185294..f9f45ba2a3 100644 --- a/docs/modules/ROOT/pages/reference/extensions/grpc.adoc +++ b/docs/modules/ROOT/pages/reference/extensions/grpc.adoc @@ -50,47 +50,24 @@ endif::[] [id="extensions-grpc-usage-protobuf-generated-code"] === Protobuf generated code -You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC service stubs with protobuf. - -[id="extensions-grpc-usage-protobuf-maven-plugin"] -==== protobuf-maven-plugin - -The `protobuf-maven-plugin` can generate service stubs for `.proto` files. Below is an example configuration for Maven. +Camel Quarkus gRPC can generate gRPC service stubs for `.proto` files. When using Maven, ensure that you have +enabled the `generate-code` goals of the `quarkus-maven-plugin` in your project build. [source,xml] ---- <build> - <extensions> - <extension> - <groupId>kr.motd.maven</groupId> - <artifactId>os-maven-plugin</artifactId> - <version>{os-maven-plugin-version}</version> - </extension> - </extensions> - <plugins> <plugin> - <groupId>org.xolstice.maven.plugins</groupId> - <artifactId>protobuf-maven-plugin</artifactId> - <version>{protobuf-maven-plugin-version}</version> - <configuration> - <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact> - <pluginId>grpc-java</pluginId> - <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> - </configuration> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <version>${quarkus.platform.version}</version> + <extensions>true</extensions> <executions> <execution> - <id>compile</id> - <goals> - <goal>compile</goal> - <goal>compile-custom</goal> - </goals> - </execution> - <execution> - <id>test-compile</id> <goals> - <goal>test-compile</goal> - <goal>test-compile-custom</goal> + <goal>build</goal> + <goal>generate-code</goal> + <goal>generate-code-tests</goal> </goals> </execution> </executions> @@ -99,24 +76,49 @@ The `protobuf-maven-plugin` can generate service stubs for `.proto` files. Below </build> ---- -[id="extensions-grpc-usage-generated-code-limitations"] -==== Generated code limitations +With this configuration, you can put your service and message definitions into the `src/main/proto` directory and +the `quarkus-maven-plugin` will generate code from your `.proto` files. -A limitation of the generated code is that it is annotated with the non Jakarta EE 10 friendly `@javax.annotation.Generated`. +[id="extensions-grpc-usage-scanning-proto-files-with-imports"] +==== Scanning `proto` files with imports -To avoid compilation issues, the `grpc-java` project recommendation is to add a `provided` scoped dependency like this: +The Protocol Buffers specification provides a way to import proto files. You can control the scope of dependencies to +scan by adding configuration property `quarkus.camel.grpc.codegen.scan-for-imports` property to `application.properties`. +The available options are outlined below. -[source,xml] +* `all` - Scan all dependencies +* `none` - Disable dependency scanning. Use only the proto definitions defined in `src/main/proto` or `src/test/proto` +* `groupId1:artifactId1,groupId2:artifactId2` - Scan only the dependencies matching the `groupId` and `artifactId` list + +The default value is `com.google.protobuf:protobuf-java`. + +[id="extensions-grpc-usage-scanning-proto-files-from-dependencies"] +==== Scanning `proto` files from dependencies + +If you have proto files shared across multiple dependencies, you can generate gRPC service stubs for them by adding +configuration property `quarkus.camel.grpc.codegen.scan-for-proto` to `application.properties`. + +First add a dependency for the artifact(s) containing proto files to your project. Next, enable proto file +dependency scanning. + +[source,properties] ---- -<dependency> - <groupId>org.apache.tomcat</groupId> - <artifactId>annotations-api</artifactId> - <version>6.0.53</version> - <scope>provided</scope> -</dependency> +quarkus.camel.grpc.codegen.scan-for-proto=org.my.groupId1:my-artifact-id-1,org.my.groupId2:my-artifact-id-2 ---- -Alternatively, you can use Maven or Gradle plugins to iterate over the generated code (found at `target/generated-sources` for Maven) and replace all instances of `@javax.annotation.Generated` with `@jakarta.annotation.Generated`. +It is possible to include / exclude specific proto files from dependency scanning via configuration properties. + +The configuration property name suffix is the Maven `groupId` / `artifactId` for the dependency to configure includes / excludes on. +Paths are relative to the classpath location of the proto files within the dependency. Paths can be an explicit path to a proto file, +or as glob patterns to include / exclude multiple files. + +[source,properties] +---- +quarkus.camel.grpc.codegen.scan-for-proto-includes."<groupId>\:<artifactId>"=foo/**,bar/**,baz/a-proto.proto +quarkus.camel.grpc.codegen.scan-for-proto-excludes."<groupId>\:<artifactId>"=foo/private/**,baz/another-proto.proto +---- + +NOTE: The `:` character within property keys must be escaped with `\`. [id="extensions-grpc-usage-accessing-classpath-resources-in-native-mode"] === Accessing classpath resources in native mode @@ -149,3 +151,54 @@ More information about selecting resources for inclusion in the native executabl At present there is no support for integrating Camel Quarkus gRPC with Quarkus gRPC. If you have both the `camel-quarkus-grpc` and `quarkus-grpc` extension dependency on the classpath, you are likely to encounter problems at build time when compiling your application. + +[id="extensions-grpc-additional-camel-quarkus-configuration"] +== Additional Camel Quarkus configuration + +[width="100%",cols="80,5,15",options="header"] +|=== +| Configuration property | Type | Default + + +|icon:lock[title=Fixed at build time] [[quarkus.camel.grpc.codegen.enabled]]`link:#quarkus.camel.grpc.codegen.enabled[quarkus.camel.grpc.codegen.enabled]` + +If `true`, Camel Quarkus gRPC code generation is run for .proto files discovered from the `proto` directory, or from dependencies specified in the `scan-for-proto` or `scan-for-imports` options. When `false`, code generation for .proto files is disabled. +| `boolean` +| `true` + +|icon:lock[title=Fixed at build time] [[quarkus.camel.grpc.codegen.scan-for-proto]]`link:#quarkus.camel.grpc.codegen.scan-for-proto[quarkus.camel.grpc.codegen.scan-for-proto]` + +Camel Quarkus gRPC code generation can scan application dependencies for .proto files to generate Java stubs from them. This property sets the scope of the dependencies to scan. Applicable values: + + - _none_ - default - don't scan dependencies + - a comma separated list of _groupId:artifactId_ coordinates to scan + - _all_ - scan all dependencies +| `string` +| `none` + +|icon:lock[title=Fixed at build time] [[quarkus.camel.grpc.codegen.scan-for-imports]]`link:#quarkus.camel.grpc.codegen.scan-for-imports[quarkus.camel.grpc.codegen.scan-for-imports]` + +Camel Quarkus gRPC code generation can scan dependencies for .proto files that can be imported by protos in this applications. Applicable values: + + - _none_ - default - don't scan dependencies + - a comma separated list of _groupId:artifactId_ coordinates to scan + - _all_ - scan all dependencies The default is _com.google.protobuf:protobuf-java_. +| `string` +| `com.google.protobuf:protobuf-java` + +|icon:lock[title=Fixed at build time] [[quarkus.camel.grpc.codegen.scan-for-proto-includes]]`link:#quarkus.camel.grpc.codegen.scan-for-proto-includes[quarkus.camel.grpc.codegen.scan-for-proto-includes]` + +Package path or file glob pattern includes per dependency containing .proto files to be considered for inclusion. +| ``Map<String,List<String>>`` +| + +|icon:lock[title=Fixed at build time] [[quarkus.camel.grpc.codegen.scan-for-proto-excludes]]`link:#quarkus.camel.grpc.codegen.scan-for-proto-excludes[quarkus.camel.grpc.codegen.scan-for-proto-excludes]` + +Package path or file glob pattern includes per dependency containing .proto files to be considered for exclusion. +| ``Map<String,List<String>>`` +| +|=== + +[.configuration-legend] +{doc-link-icon-lock}[title=Fixed at build time] Configuration property fixed at build time. All other configuration properties are overridable at runtime. + diff --git a/extensions/grpc/codegen/pom.xml b/extensions/grpc/codegen/pom.xml new file mode 100644 index 0000000000..759840ed37 --- /dev/null +++ b/extensions/grpc/codegen/pom.xml @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-grpc-parent</artifactId> + <version>3.0.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-grpc-codegen</artifactId> + <name>Camel Quarkus :: gRPC :: Codegen</name> + + <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-core-deployment</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-devtools-utilities</artifactId> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java-util</artifactId> + <exclusions> + <exclusion> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.github.javaparser</groupId> + <artifactId>javaparser-core</artifactId> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>linux-aarch_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>linux-x86_32</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>linux-x86_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>osx-x86_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>osx-aarch_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>windows-x86_32</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protoc</artifactId> + <classifier>windows-x86_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>linux-aarch_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>linux-x86_32</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>linux-x86_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>osx-x86_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>osx-aarch_64</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>windows-x86_32</classifier> + <type>exe</type> + </dependency> + <dependency> + <groupId>io.grpc</groupId> + <artifactId>protoc-gen-grpc-java</artifactId> + <classifier>windows-x86_64</classifier> + <type>exe</type> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project> diff --git a/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcCodegenProvider.java b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcCodegenProvider.java new file mode 100644 index 0000000000..4b8f437182 --- /dev/null +++ b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcCodegenProvider.java @@ -0,0 +1,434 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.quarkus.grpc.codegen; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.stream.Stream; + +import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.bootstrap.prebuild.CodeGenException; +import io.quarkus.deployment.CodeGenContext; +import io.quarkus.deployment.CodeGenProvider; +import io.quarkus.deployment.util.ProcessUtil; +import io.quarkus.maven.dependency.ResolvedDependency; +import io.quarkus.paths.PathFilter; +import io.quarkus.runtime.util.HashUtil; +import io.quarkus.utilities.OS; +import org.eclipse.microprofile.config.Config; +import org.jboss.logging.Logger; + +import static java.util.Arrays.asList; + +/** + * Custom {@link CodeGenProvider} for Camel Quarkus gRPC. Based on the original Quarkus gRPC implementation: + * <p> + * <a href= + * "https://github.com/quarkusio/quarkus/tree/main/extensions/grpc/codegen">https://github.com/quarkusio/quarkus/tree/main/extensions/grpc/codegen</a> + * <p> + * The implementation does not include additional logic for features not supported in Camel gRPC, such as integration + * with Mutiny and CDI. + */ +public class CamelQuarkusGrpcCodegenProvider implements CodeGenProvider { + private static final Logger LOG = Logger.getLogger(CamelQuarkusGrpcCodegenProvider.class); + private static final String EXE = "exe"; + private static final String PROTO = ".proto"; + private static final String PROTOC = "protoc"; + private static final String PROTOC_GROUP_ID = "com.google.protobuf"; + private static final String SCAN_DEPENDENCIES_FOR_PROTO = "quarkus.camel.grpc.codegen.scan-for-proto"; + private static final String SCAN_DEPENDENCIES_FOR_PROTO_INCLUDE_PATTERN = "quarkus.camel.grpc.codegen.scan-for-proto-includes.\"%s\""; + private static final String SCAN_DEPENDENCIES_FOR_PROTO_EXCLUDE_PATTERN = "quarkus.camel.grpc.codegen.scan-for-proto-excludes.\"%s\""; + private static final String SCAN_FOR_IMPORTS = "quarkus.camel.grpc.codegen.scan-for-imports"; + + private Executables executables; + + @Override + public String providerId() { + return "camel-quarkus-grpc"; + } + + @Override + public String inputExtension() { + return "proto"; + } + + @Override + public String inputDirectory() { + return "proto"; + } + + @Override + public boolean trigger(CodeGenContext context) throws CodeGenException { + final Config config = context.config(); + if (!config.getValue("quarkus.camel.grpc.codegen.enabled", Boolean.class)) { + LOG.info("Skipping " + this.getClass() + " invocation on user's request"); + return false; + } + + Path outDir = context.outDir(); + Path workDir = context.workDir(); + Set<String> protoDirs = new HashSet<>(); + + try { + List<String> protoFiles = new ArrayList<>(); + if (Files.isDirectory(context.inputDir())) { + try (Stream<Path> protoFilesPaths = Files.walk(context.inputDir())) { + protoFilesPaths + .filter(Files::isRegularFile) + .filter(s -> s.toString().endsWith(PROTO)) + .map(Path::normalize) + .map(Path::toAbsolutePath) + .map(Path::toString) + .forEach(protoFiles::add); + protoDirs.add(context.inputDir().normalize().toAbsolutePath().toString()); + } + } + Path dirWithProtosFromDependencies = workDir.resolve("protoc-protos-from-dependencies"); + Collection<Path> protoFilesFromDependencies = gatherProtosFromDependencies(dirWithProtosFromDependencies, protoDirs, + context); + if (!protoFilesFromDependencies.isEmpty()) { + protoFilesFromDependencies.stream() + .map(Path::normalize) + .map(Path::toAbsolutePath) + .map(Path::toString) + .forEach(protoFiles::add); + } + + if (!protoFiles.isEmpty()) { + initExecutables(workDir, context.applicationModel()); + + Path protocDependenciesDir = workDir.resolve("protoc-dependencies"); + Collection<String> protosToImport = gatherDirectoriesWithImports(protocDependenciesDir, context); + + if (!protoFilesFromDependencies.isEmpty() && !protosToImport.isEmpty()) { + // Clean up potential duplicates that can exist when scan-for-imports artifacts clash with scan-for-proto configs + protoFiles.forEach(file -> { + if (!file.contains(context.inputDir().toString())) { + String relativeFileName = file.replace(dirWithProtosFromDependencies.toString(), ""); + Path path = Paths.get(protocDependenciesDir.toAbsolutePath().toString(), relativeFileName); + if (Files.exists(path)) { + LOG.debugf("Cleaning up duplicate proto file %s", path); + try { + Files.delete(path); + } catch (IOException e) { + LOG.errorf("Failed cleaning up duplicate proto file %s", e); + } + } + } + }); + } + + List<String> command = new ArrayList<>(); + command.add(executables.protoc.toString()); + for (String protoImportDir : protosToImport) { + command.add(String.format("-I=%s", escapeWhitespace(protoImportDir))); + } + for (String protoDir : protoDirs) { + command.add(String.format("-I=%s", escapeWhitespace(protoDir))); + } + + command.addAll(asList("--plugin=protoc-gen-grpc=" + executables.grpc, + "--grpc_out=" + outDir, + "--java_out=" + outDir)); + command.addAll(protoFiles); + + ProcessBuilder processBuilder = new ProcessBuilder(command); + + final Process process = ProcessUtil.launchProcess(processBuilder, context.shouldRedirectIO()); + int resultCode = process.waitFor(); + if (resultCode != 0) { + throw new CodeGenException("Failed to generate Java classes from proto files: " + protoFiles + + " to " + outDir.toAbsolutePath() + " with command " + String.join(" ", command)); + } + new CamelQuarkusGrpcPostProcessor(outDir).process(); + LOG.info("Successfully finished generating and post-processing sources from proto files"); + return true; + } + } catch (IOException | InterruptedException e) { + throw new CodeGenException( + "Failed to generate java files from proto file in " + context.inputDir().toAbsolutePath(), e); + } + + return false; + } + + private static void copySanitizedProtoFile(ResolvedDependency artifact, Path protoPath, Path outProtoPath) + throws IOException { + boolean genericServicesFound = false; + + try (var reader = Files.newBufferedReader(protoPath); + var writer = Files.newBufferedWriter(outProtoPath)) { + + String line = reader.readLine(); + while (line != null) { + // filter java_generic_services to avoid "Tried to write the same file twice" + // when set to true. Generic services are deprecated and replaced by classes generated by + // this plugin + if (!line.contains("java_generic_services")) { + writer.write(line); + writer.newLine(); + } else { + genericServicesFound = true; + } + + line = reader.readLine(); + } + } + + if (genericServicesFound) { + LOG.infof("Ignoring option java_generic_services in %s:%s%s.", artifact.getGroupId(), artifact.getArtifactId(), + protoPath); + } + } + + private Collection<Path> gatherProtosFromDependencies(Path workDir, Set<String> protoDirectories, + CodeGenContext context) throws CodeGenException { + if (context.test()) { + return Collections.emptyList(); + } + Config properties = context.config(); + String scanDependencies = properties.getValue(SCAN_DEPENDENCIES_FOR_PROTO, String.class); + + if ("none".equalsIgnoreCase(scanDependencies)) { + return Collections.emptyList(); + } + boolean scanAll = "all".equalsIgnoreCase(scanDependencies); + + List<String> dependenciesToScan = asList(scanDependencies.split(",")); + + ApplicationModel appModel = context.applicationModel(); + List<Path> protoFilesFromDependencies = new ArrayList<>(); + for (ResolvedDependency artifact : appModel.getRuntimeDependencies()) { + String packageId = String.format("%s:%s", artifact.getGroupId(), artifact.getArtifactId()); + Collection<String> includes = properties + .getOptionalValues(String.format(SCAN_DEPENDENCIES_FOR_PROTO_INCLUDE_PATTERN, packageId), String.class) + .orElse(List.of()); + + Collection<String> excludes = properties + .getOptionalValues(String.format(SCAN_DEPENDENCIES_FOR_PROTO_EXCLUDE_PATTERN, packageId), String.class) + .orElse(List.of()); + + if (scanAll + || dependenciesToScan.contains(packageId)) { + extractProtosFromArtifact(workDir, protoFilesFromDependencies, protoDirectories, artifact, includes, excludes, + true); + } + } + return protoFilesFromDependencies; + } + + @Override + public boolean shouldRun(Path sourceDir, Config config) { + return CodeGenProvider.super.shouldRun(sourceDir, config) + || isGeneratingFromAppDependenciesEnabled(config); + } + + private boolean isGeneratingFromAppDependenciesEnabled(Config config) { + return config.getOptionalValue(SCAN_DEPENDENCIES_FOR_PROTO, String.class) + .filter(value -> !"none".equals(value)).isPresent(); + } + + private Collection<String> gatherDirectoriesWithImports(Path workDir, CodeGenContext context) throws CodeGenException { + Config properties = context.config(); + + String scanForImports = properties.getOptionalValue(SCAN_FOR_IMPORTS, String.class) + .orElse("com.google.protobuf:protobuf-java"); + + if ("none".equals(scanForImports.toLowerCase(Locale.getDefault()))) { + return Collections.emptyList(); + } + + boolean scanAll = "all".equals(scanForImports.toLowerCase(Locale.getDefault())); + List<String> dependenciesToScan = Arrays.asList(scanForImports.split(",")); + + Set<String> importDirectories = new HashSet<>(); + ApplicationModel appModel = context.applicationModel(); + for (ResolvedDependency artifact : appModel.getRuntimeDependencies()) { + if (scanAll + || dependenciesToScan.contains( + String.format("%s:%s", artifact.getGroupId(), artifact.getArtifactId()))) { + extractProtosFromArtifact(workDir, new ArrayList<>(), importDirectories, artifact, List.of(), + List.of(), false); + } + } + return importDirectories; + } + + private void extractProtosFromArtifact(Path workDir, Collection<Path> protoFiles, + Set<String> protoDirectories, ResolvedDependency artifact, Collection<String> filesToInclude, + Collection<String> filesToExclude, boolean isDependency) throws CodeGenException { + + try { + artifact.getContentTree(new PathFilter(filesToInclude, filesToExclude)).walk( + pathVisit -> { + Path path = pathVisit.getPath(); + if (Files.isRegularFile(path) && path.getFileName().toString().endsWith(PROTO)) { + Path root = pathVisit.getRoot(); + if (Files.isDirectory(root)) { + protoFiles.add(path); + protoDirectories.add(path.getParent().normalize().toAbsolutePath().toString()); + } else { // archive + Path relativePath = path.getRoot().relativize(path); + Path protoUnzipDir = workDir + .resolve(HashUtil.sha1(root.normalize().toAbsolutePath().toString())) + .normalize().toAbsolutePath(); + try { + Files.createDirectories(protoUnzipDir); + protoDirectories.add(protoUnzipDir.toString()); + } catch (IOException e) { + throw new GrpcCodeGenException("Failed to create directory: " + protoUnzipDir, e); + } + Path outPath = protoUnzipDir; + for (Path part : relativePath) { + outPath = outPath.resolve(part.toString()); + } + try { + Files.createDirectories(outPath.getParent()); + if (isDependency) { + copySanitizedProtoFile(artifact, path, outPath); + } else { + Files.copy(path, outPath, StandardCopyOption.REPLACE_EXISTING); + } + protoFiles.add(outPath); + } catch (IOException e) { + throw new GrpcCodeGenException("Failed to extract proto file" + path + " to target: " + + outPath, e); + } + } + } + }); + } catch (GrpcCodeGenException e) { + throw new CodeGenException(e.getMessage(), e); + } + } + + private String escapeWhitespace(String path) { + if (OS.determineOS() == OS.LINUX) { + return path.replace(" ", "\\ "); + } else { + return path; + } + } + + private void initExecutables(Path workDir, ApplicationModel model) throws CodeGenException { + if (executables == null) { + Path protocPath; + String protocPathProperty = System.getProperty("quarkus.grpc.protoc-path"); + String classifier = System.getProperty("quarkus.grpc.protoc-os-classifier", osClassifier()); + if (protocPathProperty == null) { + protocPath = findArtifactPath(model, PROTOC_GROUP_ID, PROTOC, classifier, EXE); + } else { + protocPath = Paths.get(protocPathProperty); + } + Path protocExe = makeExecutableFromPath(workDir, PROTOC_GROUP_ID, PROTOC, classifier, "exe", protocPath); + + Path protocGrpcPluginExe = prepareExecutable(workDir, model, + "io.grpc", "protoc-gen-grpc-java", classifier, "exe"); + + executables = new Executables(protocExe, protocGrpcPluginExe); + } + } + + private Path prepareExecutable(Path buildDir, ApplicationModel model, + String groupId, String artifactId, String classifier, String packaging) throws CodeGenException { + Path artifactPath = findArtifactPath(model, groupId, artifactId, classifier, packaging); + + return makeExecutableFromPath(buildDir, groupId, artifactId, classifier, packaging, artifactPath); + } + + private Path makeExecutableFromPath(Path buildDir, String groupId, String artifactId, String classifier, String packaging, + Path artifactPath) throws CodeGenException { + Path exe = buildDir.resolve(String.format("%s-%s-%s-%s", groupId, artifactId, classifier, packaging)); + + if (Files.exists(exe)) { + return exe; + } + + if (artifactPath == null) { + String location = String.format("%s:%s:%s:%s", groupId, artifactId, classifier, packaging); + throw new CodeGenException("Failed to find " + location + " among dependencies"); + } + + try { + Files.copy(artifactPath, exe, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw new CodeGenException("Failed to copy file: " + artifactPath + " to " + exe, e); + } + if (!exe.toFile().setExecutable(true)) { + throw new CodeGenException("Failed to make the file executable: " + exe); + } + return exe; + } + + private static Path findArtifactPath(ApplicationModel model, String groupId, String artifactId, String classifier, + String packaging) { + Path artifactPath = null; + + for (ResolvedDependency artifact : model.getDependencies()) { + if (groupId.equals(artifact.getGroupId()) + && artifactId.equals(artifact.getArtifactId()) + && classifier.equals(artifact.getClassifier()) + && packaging.equals(artifact.getType())) { + artifactPath = artifact.getResolvedPaths().getSinglePath(); + } + } + return artifactPath; + } + + private String osClassifier() throws CodeGenException { + String architecture = OS.getArchitecture(); + switch (OS.determineOS()) { + case LINUX: + return "linux-" + architecture; + case WINDOWS: + return "windows-" + architecture; + case MAC: + return "osx-" + architecture; + default: + throw new CodeGenException( + "Unsupported OS, please use maven plugin instead to generate Java classes from proto files"); + } + } + + private static class Executables { + final Path protoc; + final Path grpc; + + Executables(Path protoc, Path grpc) { + this.protoc = protoc; + this.grpc = grpc; + } + } + + private static class GrpcCodeGenException extends RuntimeException { + private GrpcCodeGenException(String message, Exception cause) { + super(message, cause); + } + } + +} diff --git a/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcPostProcessor.java b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcPostProcessor.java new file mode 100644 index 0000000000..efd44afebd --- /dev/null +++ b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcPostProcessor.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.quarkus.grpc.codegen; + +import java.io.File; +import java.nio.file.Path; + +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.body.TypeDeclaration; +import com.github.javaparser.ast.expr.NormalAnnotationExpr; +import com.github.javaparser.ast.visitor.ModifierVisitor; +import com.github.javaparser.ast.visitor.Visitable; +import com.github.javaparser.utils.SourceRoot; +import org.jboss.logging.Logger; + +/** + * Post processor for generated proto classes. + */ +public class CamelQuarkusGrpcPostProcessor { + private static final Logger LOG = Logger.getLogger(CamelQuarkusGrpcPostProcessor.class); + private static final String JAVAX_GENERATED = "javax" + ".annotation.Generated"; + private static final String JAKARTA_GENERATED = "jakarta.annotation.Generated"; + private final Path root; + + public CamelQuarkusGrpcPostProcessor(Path root) { + this.root = root; + } + + public static void main(String[] args) { + for (String arg : args) { + Path path = new File(arg).toPath(); + CamelQuarkusGrpcPostProcessor postProcessor = new CamelQuarkusGrpcPostProcessor(path); + postProcessor.process(); + } + } + + public void process() { + SourceRoot sr = new SourceRoot(root); + try { + sr.parse("", (localPath, absolutePath, result) -> { + if (result.isSuccessful()) { + CompilationUnit unit = result.getResult().orElseThrow(); + if (unit.getPrimaryType().isPresent()) { + TypeDeclaration<?> type = unit.getPrimaryType().get(); + process(unit, type); + return SourceRoot.Callback.Result.SAVE; + } + } else { + LOG.errorf( + "Unable to parse a protoc generated class, skipping post-processing for this " + + "file. Reported problems are %s", + result.toString()); + } + + return SourceRoot.Callback.Result.DONT_SAVE; + }); + } catch (Exception e) { + LOG.error("Unable to parse protoc generated classes - skipping gRPC post processing", e); + } + } + + private void process(CompilationUnit unit, TypeDeclaration<?> primary) { + LOG.debugf("Post-processing %s", primary.getFullyQualifiedName().orElse(primary.getNameAsString())); + unit.accept(new ModifierVisitor<Void>() { + @Override + public Visitable visit(NormalAnnotationExpr n, Void arg) { + // Replace javax.annotation.Generated with the jakarta equivalent + // https://github.com/grpc/grpc-java/issues/9179 + if (n.getNameAsString().equals(JAVAX_GENERATED)) { + n.setName(JAKARTA_GENERATED); + } + return super.visit(n, arg); + } + }, null); + } +} diff --git a/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider b/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider new file mode 100644 index 0000000000..16ab0e7338 --- /dev/null +++ b/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider @@ -0,0 +1 @@ +org.apache.camel.quarkus.grpc.codegen.CamelQuarkusGrpcCodegenProvider \ No newline at end of file diff --git a/extensions/grpc/deployment/pom.xml b/extensions/grpc/deployment/pom.xml index bd471510df..f7a8ef6381 100644 --- a/extensions/grpc/deployment/pom.xml +++ b/extensions/grpc/deployment/pom.xml @@ -38,6 +38,10 @@ <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-core-deployment</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-grpc-codegen</artifactId> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-grpc</artifactId> diff --git a/extensions/grpc/pom.xml b/extensions/grpc/pom.xml index b9958962b6..c8a039cdf0 100644 --- a/extensions/grpc/pom.xml +++ b/extensions/grpc/pom.xml @@ -31,6 +31,7 @@ <packaging>pom</packaging> <modules> + <module>codegen</module> <module>deployment</module> <module>runtime</module> </modules> diff --git a/extensions/grpc/runtime/src/main/doc/usage.adoc b/extensions/grpc/runtime/src/main/doc/usage.adoc index 1bfc0a2eee..a6f686659c 100644 --- a/extensions/grpc/runtime/src/main/doc/usage.adoc +++ b/extensions/grpc/runtime/src/main/doc/usage.adoc @@ -1,45 +1,23 @@ === Protobuf generated code -You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC service stubs with protobuf. - -==== protobuf-maven-plugin - -The `protobuf-maven-plugin` can generate service stubs for `.proto` files. Below is an example configuration for Maven. +Camel Quarkus gRPC can generate gRPC service stubs for `.proto` files. When using Maven, ensure that you have +enabled the `generate-code` goals of the `quarkus-maven-plugin` in your project build. [source,xml] ---- <build> - <extensions> - <extension> - <groupId>kr.motd.maven</groupId> - <artifactId>os-maven-plugin</artifactId> - <version>{os-maven-plugin-version}</version> - </extension> - </extensions> - <plugins> <plugin> - <groupId>org.xolstice.maven.plugins</groupId> - <artifactId>protobuf-maven-plugin</artifactId> - <version>{protobuf-maven-plugin-version}</version> - <configuration> - <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact> - <pluginId>grpc-java</pluginId> - <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> - </configuration> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <version>${quarkus.platform.version}</version> + <extensions>true</extensions> <executions> <execution> - <id>compile</id> - <goals> - <goal>compile</goal> - <goal>compile-custom</goal> - </goals> - </execution> - <execution> - <id>test-compile</id> <goals> - <goal>test-compile</goal> - <goal>test-compile-custom</goal> + <goal>build</goal> + <goal>generate-code</goal> + <goal>generate-code-tests</goal> </goals> </execution> </executions> @@ -48,23 +26,47 @@ The `protobuf-maven-plugin` can generate service stubs for `.proto` files. Below </build> ---- -==== Generated code limitations +With this configuration, you can put your service and message definitions into the `src/main/proto` directory and +the `quarkus-maven-plugin` will generate code from your `.proto` files. -A limitation of the generated code is that it is annotated with the non Jakarta EE 10 friendly `@javax.annotation.Generated`. +==== Scanning `proto` files with imports -To avoid compilation issues, the `grpc-java` project recommendation is to add a `provided` scoped dependency like this: +The Protocol Buffers specification provides a way to import proto files. You can control the scope of dependencies to +scan by adding configuration property `quarkus.camel.grpc.codegen.scan-for-imports` property to `application.properties`. +The available options are outlined below. -[source,xml] +* `all` - Scan all dependencies +* `none` - Disable dependency scanning. Use only the proto definitions defined in `src/main/proto` or `src/test/proto` +* `groupId1:artifactId1,groupId2:artifactId2` - Scan only the dependencies matching the `groupId` and `artifactId` list + +The default value is `com.google.protobuf:protobuf-java`. + +==== Scanning `proto` files from dependencies + +If you have proto files shared across multiple dependencies, you can generate gRPC service stubs for them by adding +configuration property `quarkus.camel.grpc.codegen.scan-for-proto` to `application.properties`. + +First add a dependency for the artifact(s) containing proto files to your project. Next, enable proto file +dependency scanning. + +[source,properties] +---- +quarkus.camel.grpc.codegen.scan-for-proto=org.my.groupId1:my-artifact-id-1,org.my.groupId2:my-artifact-id-2 +---- + +It is possible to include / exclude specific proto files from dependency scanning via configuration properties. + +The configuration property name suffix is the Maven `groupId` / `artifactId` for the dependency to configure includes / excludes on. +Paths are relative to the classpath location of the proto files within the dependency. Paths can be an explicit path to a proto file, +or as glob patterns to include / exclude multiple files. + +[source,properties] ---- -<dependency> - <groupId>org.apache.tomcat</groupId> - <artifactId>annotations-api</artifactId> - <version>6.0.53</version> - <scope>provided</scope> -</dependency> +quarkus.camel.grpc.codegen.scan-for-proto-includes."<groupId>\:<artifactId>"=foo/**,bar/**,baz/a-proto.proto +quarkus.camel.grpc.codegen.scan-for-proto-excludes."<groupId>\:<artifactId>"=foo/private/**,baz/another-proto.proto ---- -Alternatively, you can use Maven or Gradle plugins to iterate over the generated code (found at `target/generated-sources` for Maven) and replace all instances of `@javax.annotation.Generated` with `@jakarta.annotation.Generated`. +NOTE: The `:` character within property keys must be escaped with `\`. === Accessing classpath resources in native mode diff --git a/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/GrpcBuildTimeConfig.java b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/GrpcBuildTimeConfig.java new file mode 100644 index 0000000000..0f7a3eda56 --- /dev/null +++ b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/GrpcBuildTimeConfig.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.camel.quarkus.grpc.runtime; + +import java.util.List; +import java.util.Map; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.annotations.ConfigPhase; +import io.quarkus.runtime.annotations.ConfigRoot; + +@ConfigRoot(name = "camel.grpc", phase = ConfigPhase.BUILD_TIME) +public class GrpcBuildTimeConfig { + /** + * Build time configuration options for Camel Quarkus gRPC code generator. + */ + @ConfigItem + public CodeGenConfig codegen; + + @ConfigGroup + public static class CodeGenConfig { + /** + * If {@code true}, Camel Quarkus gRPC code generation is run for .proto files discovered from the {@code proto} + * directory, or from dependencies specified in the {@code scan-for-proto} or {@code scan-for-imports} options. When + * {@code false}, code generation for .proto files is disabled. + */ + @ConfigItem(defaultValue = "true") + public boolean enabled; + + /** + * Camel Quarkus gRPC code generation can scan application dependencies for .proto files to generate Java stubs + * from them. + * This property sets the scope of the dependencies to scan. + * Applicable values: + * <ul> + * <li><i>none</i> - default - don't scan dependencies</li> + * <li>a comma separated list of <i>groupId:artifactId</i> coordinates to scan</li> + * <li><i>all</i> - scan all dependencies</li> + * </ul> + */ + @ConfigItem(defaultValue = "none") + public String scanForProto; + + /** + * Camel Quarkus gRPC code generation can scan dependencies for .proto files that can be imported by protos in this + * applications. + * Applicable values: + * <ul> + * <li><i>none</i> - default - don't scan dependencies</li> + * <li>a comma separated list of <i>groupId:artifactId</i> coordinates to scan</li> + * <li><i>all</i> - scan all dependencies</li> + * </ul> + * + * The default is <i>com.google.protobuf:protobuf-java</i>. + */ + @ConfigItem(defaultValue = "com.google.protobuf:protobuf-java") + public String scanForImports; + + /** + * Package path or file glob pattern includes per dependency containing .proto files to be considered for inclusion. + */ + @ConfigItem + public Map<String, List<String>> scanForProtoIncludes; + + /** + * Package path or file glob pattern includes per dependency containing .proto files to be considered for exclusion. + */ + @ConfigItem + public Map<String, List<String>> scanForProtoExcludes; + } +} diff --git a/integration-tests-support/grpc/pom.xml b/integration-tests-support/grpc/pom.xml new file mode 100644 index 0000000000..ed38040e5c --- /dev/null +++ b/integration-tests-support/grpc/pom.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests-support</artifactId> + <version>3.0.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>camel-quarkus-integration-tests-support-grpc</artifactId> + <name>Camel Quarkus :: Integration Tests :: gRPC :: Support</name> +</project> diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/a/proto-a.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/a/proto-a.proto new file mode 100644 index 0000000000..f9fc661b41 --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/a/proto-a.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.a"; +option java_outer_classname = "PingPongProtoA"; + +package org.acme.proto.a; + +service TestA { + rpc PingSyncSync (PingRequestA) returns (PongResponseA) {} +} + +message PingRequestA { + string ping_name = 1; +} + +message PongResponseA { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/b/proto-b.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/b/proto-b.proto new file mode 100644 index 0000000000..4aae4b2a34 --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/b/proto-b.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.b"; +option java_outer_classname = "PingPongProtoB"; + +package org.acme.proto.b; + +service TestB { + rpc PingSyncSync (PingRequestB) returns (PongResponseB) {} +} + +message PingRequestB { + string ping_name = 1; +} + +message PongResponseB { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/proto-c-1.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/proto-c-1.proto new file mode 100644 index 0000000000..6d0c48f7da --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/proto-c-1.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.c"; +option java_outer_classname = "PingPongProtoC"; + +package org.acme.proto.c; + +service TestC { + rpc PingSyncSync (PingRequestC) returns (PongResponseC) {} +} + +message PingRequestC { + string ping_name = 1; +} + +message PongResponseC { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/package/proto-c-3.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/package/proto-c-3.proto new file mode 100644 index 0000000000..7a023479cc --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/package/proto-c-3.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.c.sub.dir"; +option java_outer_classname = "PingPongProtoC"; + +package org.acme.proto.c.sub.dir; + +service TestC { + rpc PingSyncSync (PingRequestC) returns (PongResponseC) {} +} + +message PingRequestC { + string ping_name = 1; +} + +message PongResponseC { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/proto-c-2.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/proto-c-2.proto new file mode 100644 index 0000000000..533c40ca33 --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/proto-c-2.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.c.sub"; +option java_outer_classname = "PingPongProtoC"; + +package org.acme.proto.c.sub; + +service TestC { + rpc PingSyncSync (PingRequestC) returns (PongResponseC) {} +} + +message PingRequestC { + string ping_name = 1; +} + +message PongResponseC { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/proto-d-1.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/proto-d-1.proto new file mode 100644 index 0000000000..49b2d57cc3 --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/proto-d-1.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.d"; +option java_outer_classname = "PingPongProtoD"; + +package org.acme.proto.d; + +service TestD { + rpc PingSyncSync (PingRequestD) returns (PongResponseD) {} +} + +message PingRequestD { + string ping_name = 1; +} + +message PongResponseD { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/package/proto-d-3.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/package/proto-d-3.proto new file mode 100644 index 0000000000..234b487c24 --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/package/proto-d-3.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.d.sub.dir"; +option java_outer_classname = "PingPongProtoD"; + +package org.acme.proto.sub.dir.d; + +service TestD { + rpc PingSyncSync (PingRequestD) returns (PongResponseD) {} +} + +message PingRequestD { + string ping_name = 1; +} + +message PongResponseD { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/proto-d-2.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/proto-d-2.proto new file mode 100644 index 0000000000..2cf0e8715b --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/proto-d-2.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.c.sub"; +option java_outer_classname = "PingPongProtoD"; + +package org.acme.proto.d.sub; + +service TestD { + rpc PingSyncSync (PingRequestD) returns (PongResponseD) {} +} + +message PingRequestD { + string ping_name = 1; +} + +message PongResponseD { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/common.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/common.proto new file mode 100644 index 0000000000..9daa38a04b --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/common.proto @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "org.acme.proto.e"; +option java_outer_classname = "PingPongProtoE"; + +package org.acme.proto.e; + +service TestE { + rpc PingSyncSync (PingRequestE) returns (PongResponseE) {} +} + +message PingRequestE { + string ping_name = 1; +} + +message PongResponseE { + string pong_name = 1; +} \ No newline at end of file diff --git a/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/proto-e.proto b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/proto-e.proto new file mode 100644 index 0000000000..4be113a27d --- /dev/null +++ b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/proto-e.proto @@ -0,0 +1,19 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +syntax = "proto3"; +import "org/acme/proto/e/common.proto"; +import "google/protobuf/timestamp.proto"; diff --git a/integration-tests-support/pom.xml b/integration-tests-support/pom.xml index 84ebb6b244..bd9292e7c7 100644 --- a/integration-tests-support/pom.xml +++ b/integration-tests-support/pom.xml @@ -45,6 +45,7 @@ <module>custom-type-converter</module> <module>custom-main-listener</module> <module>google</module> + <module>grpc</module> <module>jdbc</module> <module>kafka</module> <module>mongodb</module> diff --git a/integration-tests/grpc/pom.xml b/integration-tests/grpc/pom.xml index c2e4dfee39..843227c5dd 100644 --- a/integration-tests/grpc/pom.xml +++ b/integration-tests/grpc/pom.xml @@ -30,10 +30,6 @@ <name>Camel Quarkus :: Integration Tests :: gRPC</name> <description>Integration tests for Camel Quarkus gRPC extension</description> - <properties> - <cq.skip.protobuf>false</cq.skip.protobuf><!-- set to true via groovy below on unsupported platforms or if -Dquickly is available --> - </properties> - <dependencies> <dependency> <groupId>org.apache.camel</groupId> @@ -59,6 +55,10 @@ <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jsonb</artifactId> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests-support-grpc</artifactId> + </dependency> <!-- test dependencies --> <dependency> @@ -79,6 +79,7 @@ <dependency> <groupId>org.awaitility</groupId> <artifactId>awaitility</artifactId> + <scope>test</scope> </dependency> </dependencies> @@ -128,116 +129,16 @@ </executions> </plugin> <plugin> - <groupId>kr.motd.maven</groupId> - <artifactId>os-maven-plugin</artifactId> - <executions> - <execution> - <id>detect-os</id> - <phase>initialize</phase> - <goals> - <goal>detect</goal> - </goals> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.codehaus.gmavenplus</groupId> - <artifactId>gmavenplus-plugin</artifactId> - <executions> - <execution> - <!-- Skip code generation & tests on unsupported platforms --> - <id>skip-plugins-on-unsupported-platform</id> - <phase>generate-sources</phase> - <goals> - <goal>execute</goal> - </goals> - <configuration> - <scripts> - <script> - String platformUnsupported = project.properties['os.detected.classifier'].matches('^.*?(linux|windows|osx)-x86.*$') ? 'false' : 'true' - project.properties['skipTests'] = platformUnsupported - project.properties['cq.skip.protobuf'] = platformUnsupported || project.properties.containsKey('quickly') - </script> - </scripts> - </configuration> - </execution> - <execution> - <!-- - Hack around grpc-java protobuf generator tagging generated classes with javax.annotation.Generated. - - This avoids implementing the recommendation to add a dependency on org.apache.tomcat:annotations-api: - - https://github.com/grpc/grpc-java#download - - Hopefully this will eventually get fixed for the Jakarta 10+ world: - - https://github.com/grpc/grpc-java/issues/9179 - --> - <id>strip-javax-generated-annotation</id> - <phase>process-sources</phase> - <goals> - <goal>execute</goal> - </goals> - <configuration> - <scripts> - <script> - def buildDir = project.build.directory - new File("${buildDir}/generated-sources").eachFileRecurse { file -> - if (file.name.endsWith('.java') && file.text.contains('javax.annotation.Generated')) { - def modifiedContent = file.text.replace('javax', 'jakarta') - file.write(modifiedContent) - } - } - </script> - </scripts> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.xolstice.maven.plugins</groupId> - <artifactId>protobuf-maven-plugin</artifactId> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> <extensions>true</extensions> <executions> <execution> <goals> - <goal>compile</goal> - <goal>compile-custom</goal> - </goals> - <phase>generate-sources</phase> - <configuration> - <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact> - <pluginId>grpc-java</pluginId> - <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> - <checkStaleness>true</checkStaleness> - <skip>${cq.skip.protobuf}</skip> - </configuration> - </execution> - </executions> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <executions> - <execution> - <id>default-compile</id> - <phase>compile</phase> - <goals> - <goal>compile</goal> + <goal>build</goal> + <goal>generate-code</goal> + <goal>generate-code-tests</goal> </goals> - <configuration> - <skipMain>${cq.skip.protobuf}</skipMain> - </configuration> - </execution> - <execution> - <id>default-testCompile</id> - <phase>test-compile</phase> - <goals> - <goal>testCompile</goal> - </goals> - <configuration> - <skip>${cq.skip.protobuf}</skip> - </configuration> </execution> </executions> </plugin> diff --git a/integration-tests/grpc/src/main/proto/pingpong.proto b/integration-tests/grpc/src/main/proto/pingpong.proto index 459a3b33af..2e09f3bc1a 100644 --- a/integration-tests/grpc/src/main/proto/pingpong.proto +++ b/integration-tests/grpc/src/main/proto/pingpong.proto @@ -16,6 +16,9 @@ */ syntax = "proto3"; +// Tests that arbitrary imports can work +import "google/protobuf/timestamp.proto"; + option java_multiple_files = true; option java_package = "org.apache.camel.quarkus.component.grpc.it.model"; option java_outer_classname = "PingPongProto"; diff --git a/integration-tests/grpc/src/main/resources/application.properties b/integration-tests/grpc/src/main/resources/application.properties index 7fb36b14c9..63661b9b4a 100644 --- a/integration-tests/grpc/src/main/resources/application.properties +++ b/integration-tests/grpc/src/main/resources/application.properties @@ -16,3 +16,11 @@ ## --------------------------------------------------------------------------- quarkus.native.resources.includes=certs/*.key,certs/*.pem,keys/*.json + +# Test codegen protobuf imports +quarkus.camel.grpc.codegen.scan-for-imports=com.google.protobuf:protobuf-java,org.apache.camel.quarkus:camel-quarkus-integration-tests-support-grpc + +# Test codegen scanning for proto files in other dependencies +quarkus.camel.grpc.codegen.scan-for-proto=org.apache.camel.quarkus:camel-quarkus-integration-tests-support-grpc +quarkus.camel.grpc.codegen.scan-for-proto-includes."org.apache.camel.quarkus\:camel-quarkus-integration-tests-support-grpc"=org/acme/proto/a/*,org/acme/proto/b/proto-b.proto,org/acme/proto/c/**,org/acme/proto/d/**,org/acme/proto/e/** +quarkus.camel.grpc.codegen.scan-for-proto-excludes."org.apache.camel.quarkus\:camel-quarkus-integration-tests-support-grpc"=org/acme/proto/d/*,org/acme/proto/d/sub/proto-d-2.proto,org/acme/proto/d/sub/package** diff --git a/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java index 2a891f32b6..fdae550b34 100644 --- a/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java +++ b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java @@ -17,6 +17,7 @@ package org.apache.camel.quarkus.component.grpc.it; import java.util.Iterator; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -39,6 +40,7 @@ import org.apache.camel.quarkus.component.grpc.it.model.PingPongGrpc.PingPongBlo import org.apache.camel.quarkus.component.grpc.it.model.PingPongGrpc.PingPongStub; import org.apache.camel.quarkus.component.grpc.it.model.PingRequest; import org.apache.camel.quarkus.component.grpc.it.model.PongResponse; +import org.apache.camel.util.StringHelper; import org.awaitility.Awaitility; import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; @@ -62,6 +64,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; @QuarkusTest @QuarkusTestResource(GrpcServerTestResource.class) @@ -574,6 +577,25 @@ class GrpcTest { } } + @ParameterizedTest + @MethodSource("generatedProtoClassNames") + public void codeGenDependencyScan(String generatedClassPackage) { + // Additional proto files scanned from org.apache.camel.quarkus:camel-quarkus-integration-tests-support-grpc + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + String packageChar = StringHelper.after(generatedClassPackage, "org.acme.proto.").replaceAll(".sub|.dir", ""); + String generatedClassName = generatedClassPackage + ".PingPongProto" + packageChar.toUpperCase(); + try { + classLoader.loadClass(generatedClassName); + if (packageChar.equals("d")) { + fail("Expected to not be able to load generated class: " + generatedClassName); + } + } catch (ClassNotFoundException e) { + if (!packageChar.equals("d")) { + fail("Expected to be able to load generated class: " + generatedClassName); + } + } + } + static Stream<Arguments> producerMethodPorts() { return Stream.of( Arguments.of("pingSyncSync", "{{camel.grpc.test.async.server.port}}"), @@ -584,6 +606,20 @@ class GrpcTest { Arguments.of("pingAsyncAsync", "{{camel.grpc.test.sync.server.port}}")); } + static List<String> generatedProtoClassNames() { + String packagePrefix = "org.acme.proto."; + return List.of( + packagePrefix + "a", + packagePrefix + "b", + packagePrefix + "c", + packagePrefix + "c.sub", + packagePrefix + "c.sub.dir", + packagePrefix + "d", + packagePrefix + "d.sub", + packagePrefix + "d.sub.dir", + packagePrefix + "e"); + } + static final class PongResponseStreamObserver implements StreamObserver<PongResponse> { private final CountDownLatch latch; private final boolean simulateError; diff --git a/pom.xml b/pom.xml index 31f015663d..146fa3282c 100644 --- a/pom.xml +++ b/pom.xml @@ -200,8 +200,6 @@ <maven-scm-plugin.version>2.0.0</maven-scm-plugin.version> <maven-shade-plugin.version>3.5.0</maven-shade-plugin.version> <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version> - <os-maven-plugin.version>1.7.1</os-maven-plugin.version> - <protobuf-maven-plugin.version>${protobuf-maven-plugin-version}</protobuf-maven-plugin.version> <rpkgtests-maven-plugin.version>1.0.0</rpkgtests-maven-plugin.version> <!-- Test container image properties --> diff --git a/poms/bom-test/pom.xml b/poms/bom-test/pom.xml index 077be210a4..df923ebe13 100644 --- a/poms/bom-test/pom.xml +++ b/poms/bom-test/pom.xml @@ -175,6 +175,11 @@ <artifactId>camel-quarkus-integration-tests-support-google</artifactId> <version>${camel-quarkus.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests-support-grpc</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-integration-test-support</artifactId> diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml index 4bab975644..58665b94e6 100644 --- a/poms/bom/pom.xml +++ b/poms/bom/pom.xml @@ -3837,6 +3837,11 @@ <artifactId>camel-quarkus-grpc-deployment</artifactId> <version>${camel-quarkus.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-grpc-codegen</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-gson</artifactId> diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml b/poms/bom/src/main/generated/flattened-full-pom.xml index fdece605a3..498a885125 100644 --- a/poms/bom/src/main/generated/flattened-full-pom.xml +++ b/poms/bom/src/main/generated/flattened-full-pom.xml @@ -3763,6 +3763,11 @@ <artifactId>camel-quarkus-grpc-deployment</artifactId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> <version>3.0.0-SNAPSHOT</version><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> + <artifactId>camel-quarkus-grpc-codegen</artifactId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> + <version>3.0.0-SNAPSHOT</version><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> <artifactId>camel-quarkus-gson</artifactId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> diff --git a/poms/bom/src/main/generated/flattened-reduced-pom.xml b/poms/bom/src/main/generated/flattened-reduced-pom.xml index 726a1de96e..69509ddae3 100644 --- a/poms/bom/src/main/generated/flattened-reduced-pom.xml +++ b/poms/bom/src/main/generated/flattened-reduced-pom.xml @@ -3763,6 +3763,11 @@ <artifactId>camel-quarkus-grpc-deployment</artifactId> <version>3.0.0-SNAPSHOT</version> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-grpc-codegen</artifactId> + <version>3.0.0-SNAPSHOT</version> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-gson</artifactId> diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml index fc09ab6bda..de31528b04 100644 --- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml +++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml @@ -3763,6 +3763,11 @@ <artifactId>camel-quarkus-grpc-deployment</artifactId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> <version>3.0.0-SNAPSHOT</version><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> + <artifactId>camel-quarkus-grpc-codegen</artifactId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> + <version>3.0.0-SNAPSHOT</version><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> + </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> <artifactId>camel-quarkus-gson</artifactId><!-- org.apache.camel.quarkus:camel-quarkus-bom:${project.version} --> diff --git a/poms/build-parent/pom.xml b/poms/build-parent/pom.xml index ca0f8efd25..64ad613061 100644 --- a/poms/build-parent/pom.xml +++ b/poms/build-parent/pom.xml @@ -71,11 +71,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>kr.motd.maven</groupId> - <artifactId>os-maven-plugin</artifactId> - <version>${os-maven-plugin.version}</version> - </plugin> <plugin> <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-maven-plugin</artifactId> @@ -100,11 +95,6 @@ <artifactId>jandex-maven-plugin</artifactId> <version>${jandex-maven-plugin.version}</version> </plugin> - <plugin> - <groupId>org.xolstice.maven.plugins</groupId> - <artifactId>protobuf-maven-plugin</artifactId> - <version>${protobuf-maven-plugin.version}</version> - </plugin> <plugin> <groupId>net.revelc.code.formatter</groupId> <artifactId>formatter-maven-plugin</artifactId>