Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.15.x] Backports #6729

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions docs/modules/ROOT/pages/reference/extensions/amqp.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ endif::[]

[id="extensions-amqp-usage"]
== Usage
This extension leverages https://github.com/amqphub/quarkus-qpid-jms/[Quarkus Qpid JMS]. A `ConnectionFactory` bean is created automatically
and wired into the AMQP component for you. The connection factory can be configured
via the Quarkus Qpid JMS https://github.com/amqphub/quarkus-qpid-jms#configuration[configuration options].

[id="extensions-amqp-usage-message-mapping-with-org-w3c-dom-node"]
=== Message mapping with `org.w3c.dom.Node`

Expand Down Expand Up @@ -91,11 +95,3 @@ You will also need to enable serialization for the exception classes that you in
----
@RegisterForReflection(targets = { IllegalStateException.class, MyCustomException.class }, serialization = true)
----

[id="extensions-amqp-additional-camel-quarkus-configuration"]
== Additional Camel Quarkus configuration

The extension leverages the https://github.com/amqphub/quarkus-qpid-jms/[Quarkus Qpid JMS] extension. A ConnectionFactory bean is automatically created
and wired into the AMQP component for you. The connection factory can be configured
via the Quarkus Qpid JMS https://github.com/amqphub/quarkus-qpid-jms#configuration[configuration options].

Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ In order to send the captured traces to a tracing system, you need to configure
quarkus.application.name=my-camel-application

# OTLP exporter endpoint
quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317
quarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317
----

Refer to the https://quarkus.io/guides/opentelemetry[Quarkus OpenTelemetry guide] for a full list of configuration options.
Expand All @@ -80,7 +80,7 @@ Additional exporters will be available in the Quarkiverse https://github.com/qua

When instrumenting the execution of CDI bean methods from Camel routes, you should annotate such methods with `io.opentelemetry.extension.annotations.WithSpan`. Methods annotated with `@WithSpan` will create a new Span and establish any required relationships with the current Trace context.

For example, to instrument a CDI bean from a Camel route, first ensure the appropriate methods are annotated with `@WithTrace`.
For example, to instrument a CDI bean from a Camel route, first ensure the appropriate methods are annotated with `@WithSpan`.

[source,java]
----
Expand Down
3 changes: 0 additions & 3 deletions extensions/amqp/runtime/src/main/doc/configuration.adoc

This file was deleted.

4 changes: 4 additions & 0 deletions extensions/amqp/runtime/src/main/doc/usage.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
This extension leverages https://github.com/amqphub/quarkus-qpid-jms/[Quarkus Qpid JMS]. A `ConnectionFactory` bean is created automatically
and wired into the AMQP component for you. The connection factory can be configured
via the Quarkus Qpid JMS https://github.com/amqphub/quarkus-qpid-jms#configuration[configuration options].

=== Message mapping with `org.w3c.dom.Node`

The Camel AMQP component supports message mapping between `jakarta.jms.Message` and `org.apache.camel.Message`. When wanting to convert a Camel message body type of `org.w3c.dom.Node`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,18 @@
*/
package org.apache.camel.quarkus.component.jackson.avro.deployment;

import java.util.function.BooleanSupplier;

import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
import io.quarkus.gizmo.Gizmo;
import org.apache.avro.Schema.Parser;
import org.apache.avro.file.DataFileWriter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

class JacksonAvroProcessor {
private static final String FEATURE = "camel-jackson-avro";
Expand All @@ -33,4 +41,46 @@ FeatureBuildItem feature() {
RuntimeInitializedClassBuildItem runtimeInitializedClass() {
return new RuntimeInitializedClassBuildItem(DataFileWriter.class.getName());
}

@BuildStep(onlyIfNot = { AvroParserSetValidateMethodPresent.class })
BytecodeTransformerBuildItem patchAvroJacksonCompatibility() {
// Hack to maintain avro-jackson compatibility with Avro 1.12.x
// Adds a noop version of Parser.setValidate that got removed in Avro 1.12.x.
// public Parser setValidate(boolean validate) {
// return this;
// }
return new BytecodeTransformerBuildItem.Builder()
.setClassToTransform(Parser.class.getName())
.setCacheable(true)
.setVisitorFunction((className, classVisitor) -> {
return new ClassVisitor(Gizmo.ASM_API_VERSION, classVisitor) {
@Override
public void visitEnd() {
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC, "setValidate",
"(Z)Lorg/apache/avro/Schema$Parser;", null, null);
if (mv != null) {
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(1, 2);
mv.visitEnd();
}
super.visitEnd();
}
};
})
.build();
}

static class AvroParserSetValidateMethodPresent implements BooleanSupplier {
@Override
public boolean getAsBoolean() {
try {
Parser.class.getDeclaredMethod("setValidate", boolean.class);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
}
}
4 changes: 2 additions & 2 deletions extensions/opentelemetry/runtime/src/main/doc/usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ In order to send the captured traces to a tracing system, you need to configure
quarkus.application.name=my-camel-application

# OTLP exporter endpoint
quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://localhost:4317
quarkus.otel.exporter.otlp.traces.endpoint=http://localhost:4317
----

Refer to the https://quarkus.io/guides/opentelemetry[Quarkus OpenTelemetry guide] for a full list of configuration options.
Expand All @@ -30,7 +30,7 @@ Additional exporters will be available in the Quarkiverse https://github.com/qua

When instrumenting the execution of CDI bean methods from Camel routes, you should annotate such methods with `io.opentelemetry.extension.annotations.WithSpan`. Methods annotated with `@WithSpan` will create a new Span and establish any required relationships with the current Trace context.

For example, to instrument a CDI bean from a Camel route, first ensure the appropriate methods are annotated with `@WithTrace`.
For example, to instrument a CDI bean from a Camel route, first ensure the appropriate methods are annotated with `@WithSpan`.

[source,java]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
Expand All @@ -30,14 +33,19 @@
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.avro.Schema;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.jackson.SchemaResolver;
import org.apache.camel.component.jackson.avro.JacksonAvroDataFormat;
import org.apache.commons.io.IOUtils;

@Path("/jackson-avro")
@ApplicationScoped
Expand Down Expand Up @@ -93,6 +101,34 @@ public Response avroJacksonUnMarshal(@PathParam("type") String type, byte[] mess
return builder.build();
}

@Path("/custom/mapper")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String customMapper(@QueryParam("schemaFrom") String schemaFrom) throws IOException {
AvroMapper avroMapper = new AvroMapper();
AvroSchema avroSchema;

if (schemaFrom.equals("classpath")) {
avroSchema = avroMapper.schemaFrom(JacksonAvroResource.class.getResourceAsStream("/pojo.avsc"));
} else if (schemaFrom.equals("string")) {
try (InputStream stream = JacksonAvroResource.class.getResourceAsStream("/pojo.avsc")) {
avroSchema = avroMapper.schemaFrom(IOUtils.toString(stream, StandardCharsets.UTF_8));
}
} else if (schemaFrom.equals("file")) {
java.nio.file.Path schemaFile = Paths.get("target/schema.avsc");
try (InputStream stream = JacksonAvroResource.class.getResourceAsStream("/pojo.avsc")) {
Files.write(schemaFile, stream.readAllBytes());
avroSchema = avroMapper.schemaFrom(schemaFile.toFile());
} finally {
Files.deleteIfExists(schemaFile);
}
} else {
throw new IllegalArgumentException("Unknown schema from option: " + schemaFrom);
}

return avroSchema.getAvroSchema().getName();
}

@Named
public SchemaResolver avroSchemaResolver() throws IOException {
return createSchemaResolver("/pojo.avsc");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.apache.camel.quarkus.component.jackson.avro.it.StringAppendingDeserializer.STRING_TO_APPEND;
import static org.hamcrest.Matchers.equalTo;
Expand Down Expand Up @@ -87,4 +89,15 @@ public void marshalUnmarshalWithList() {
.statusCode(200)
.body(equalTo(message));
}

@ParameterizedTest
@ValueSource(strings = { "classpath", "file", "string" })
public void customAvroMapper(String schemaFrom) {
RestAssured.given()
.queryParam("schemaFrom", schemaFrom)
.get("/jackson-avro/custom/mapper")
.then()
.statusCode(200)
.body(equalTo("Pojo"));
}
}
Loading