Skip to content

Commit

Permalink
Extend test coverage of gRPC extension
Browse files Browse the repository at this point in the history
Fixes #5155
  • Loading branch information
jamesnetherton committed Aug 11, 2023
1 parent df2bc76 commit 01f624f
Show file tree
Hide file tree
Showing 15 changed files with 732 additions and 117 deletions.
2 changes: 2 additions & 0 deletions docs/antora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ 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
Expand Down
93 changes: 85 additions & 8 deletions docs/modules/ROOT/pages/reference/extensions/grpc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,64 @@ ifeval::[{doc-show-user-guide-link} == true]
Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
endif::[]

[id="extensions-grpc-camel-quarkus-limitations"]
== Camel Quarkus limitations
[id="extensions-grpc-usage"]
== Usage
[id="extensions-grpc-usage-protobuf-generated-code"]
=== Protobuf generated code

[id="extensions-grpc-limitations-integration-with-quarkus-grpc-is-not-supported"]
=== Integration with Quarkus gRPC is not supported
You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC service stubs with protobuf.

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-usage-protobuf-maven-plugin"]
==== protobuf-maven-plugin

[id="extensions-grpc-limitations-protobuf-generated-code"]
=== Protobuf generated code
The `protobuf-maven-plugin` can generate service stubs for `.proto` files. Below is an example configuration for Maven.

You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC service stubs with protobuf. A limitation of this is that generated code is annotated with the non Jakarta EE 10 friendly `@javax.annotation.Generated`.
[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>
<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>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----

[id="extensions-grpc-usage-generated-code-limitations"]
==== Generated code limitations

A limitation of the generated code is that it is annotated with the non Jakarta EE 10 friendly `@javax.annotation.Generated`.

To avoid compilation issues, the `grpc-java` project recommendation is to add a `provided` scoped dependency like this:

Expand All @@ -72,3 +118,34 @@ To avoid compilation issues, the `grpc-java` project recommendation is to add a

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`.

[id="extensions-grpc-usage-accessing-classpath-resources-in-native-mode"]
=== Accessing classpath resources in native mode

The gRPC component has various options where resources are resolved from the classpath:

* `keyCertChainResource`
* `keyResource`
* `serviceAccountResource`
* `trustCertCollectionResource`

When using these options in native mode, you must ensure that any such resources are included in the native image.

This can be accomplished by adding the configuration property `quarkus.native.resources.includes` to `application.properties`.
For example, to include SSL / TLS keys and certificates.

[source,properties]
----
quarkus.native.resources.includes = certs/*.pem,certs.*.key
----

More information about selecting resources for inclusion in the native executable can be found in the xref:user-guide/native-mode.adoc#embedding-resource-in-native-executable[native mode guide].


[id="extensions-grpc-camel-quarkus-limitations"]
== Camel Quarkus limitations

[id="extensions-grpc-limitations-integration-with-quarkus-grpc-is-not-supported"]
=== Integration with Quarkus gRPC is not supported

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.

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.List;
import java.util.Optional;

import com.google.api.client.json.GenericJson;
import io.grpc.BindableService;
import io.grpc.stub.AbstractAsyncStub;
import io.grpc.stub.AbstractBlockingStub;
Expand Down Expand Up @@ -80,6 +81,7 @@ void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveCla
}
reflectiveClass
.produce(ReflectiveClassBuildItem.builder(AbstractStub.class.getName()).methods().build());
reflectiveClass.produce(ReflectiveClassBuildItem.builder(GenericJson.class.getName()).build());
}

@BuildStep
Expand Down
6 changes: 0 additions & 6 deletions extensions/grpc/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-grpc</artifactId>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
Expand Down
18 changes: 0 additions & 18 deletions extensions/grpc/runtime/src/main/doc/limitations.adoc
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
=== Integration with Quarkus gRPC is not supported

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.

=== Protobuf generated code

You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC service stubs with protobuf. A limitation of this is that generated code is annotated with the non Jakarta EE 10 friendly `@javax.annotation.Generated`.

To avoid compilation issues, the `grpc-java` project recommendation is to add a `provided` scoped dependency like this:

[source,xml]
----
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
----

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`.
88 changes: 88 additions & 0 deletions extensions/grpc/runtime/src/main/doc/usage.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
=== 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.

[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>
<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>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----

==== Generated code limitations

A limitation of the generated code is that it is annotated with the non Jakarta EE 10 friendly `@javax.annotation.Generated`.

To avoid compilation issues, the `grpc-java` project recommendation is to add a `provided` scoped dependency like this:

[source,xml]
----
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
----

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`.

=== Accessing classpath resources in native mode

The gRPC component has various options where resources are resolved from the classpath:

* `keyCertChainResource`
* `keyResource`
* `serviceAccountResource`
* `trustCertCollectionResource`

When using these options in native mode, you must ensure that any such resources are included in the native image.

This can be accomplished by adding the configuration property `quarkus.native.resources.includes` to `application.properties`.
For example, to include SSL / TLS keys and certificates.

[source,properties]
----
quarkus.native.resources.includes = certs/*.pem,certs.*.key
----

More information about selecting resources for inclusion in the native executable can be found in the xref:user-guide/native-mode.adoc#embedding-resource-in-native-executable[native mode guide].
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.component.grpc.it;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ForwardingClientCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

@Singleton
@Named
public class CustomClientInterceptor implements ClientInterceptor {
public static final Metadata.Key<String> PING_ID = Metadata.Key.of("pingId", Metadata.ASCII_STRING_MARSHALLER);

public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,
Channel next) {
return new ForwardingClientCall.SimpleForwardingClientCall<>(next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
headers.put(PING_ID, "100");
super.start(responseListener, headers);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* 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.component.grpc.it;

import io.grpc.Context;
import io.grpc.Contexts;
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

@Singleton
@Named
public class CustomServerInterceptor implements ServerInterceptor {
public static final Context.Key<String> RESPONSE_KEY = Context.key("consumer-response");
public static final Context.Key<String> PING_ID_CONTEXT_KEY = Context.key("pingId");
public static final Metadata.Key<String> PING_ID_METADATA_KEY = Metadata.Key.of("pingId", Metadata.ASCII_STRING_MARSHALLER);

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
Context context = Context.current()
.withValue(PING_ID_CONTEXT_KEY, headers.get(PING_ID_METADATA_KEY))
.withValue(RESPONSE_KEY, " PONG");
return Contexts.interceptCall(context, call, headers, next);
}
}
Loading

0 comments on commit 01f624f

Please sign in to comment.