diff --git a/README.adoc b/README.adoc index f5517ec3..110e73f9 100644 --- a/README.adoc +++ b/README.adoc @@ -27,7 +27,7 @@ readme's instructions. === Examples // examples: START -Number of Examples: 58 (0 deprecated) +Number of Examples: 59 (0 deprecated) [width="100%",cols="4,2,4",options="header"] |=== @@ -77,6 +77,8 @@ Number of Examples: 58 (0 deprecated) | link:master/readme.adoc[Master] (master) | Clustering | An example showing how to work with Camel's Master component and Spring Boot +| link:rest-cxf-opentelemetry/README.adoc[Rest Cxf Opentelemetry] (rest-cxf-opentelemetry) | CXF | An example showing Camel REST using CXF and OpenTelemetry with Spring Boot + | link:soap-cxf/README.adoc[Soap Cxf] (soap-cxf) | CXF | An example showing the Camel SOAP CXF | link:arangodb/README.adoc[Arangodb] (arangodb) | Database | An example showing the Camel ArangoDb component with Spring Boot diff --git a/pom.xml b/pom.xml index 318d1c9c..fb165cfd 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,7 @@ reactive-streams resilience4j rest-cxf + rest-cxf-opentelemetry rest-openapi rest-openapi-simple rest-openapi-springdoc diff --git a/rest-cxf-opentelemetry/README.adoc b/rest-cxf-opentelemetry/README.adoc new file mode 100644 index 00000000..5d09ff6a --- /dev/null +++ b/rest-cxf-opentelemetry/README.adoc @@ -0,0 +1,145 @@ +== Spring Boot Example with Camel exposing REST services using Apache CXF, collecting distributed tracing using OpenTelemetry + +=== Introduction + +This example illustrates how to use https://projects.spring.io/spring-boot/[Spring Boot] with http://camel.apache.org[Camel] and https://cxf.apache.org/[Apache CXF] implementing REST services using bottom-up approach. + +If you are using REST services directly from Camel and you want to use https://opentelemetry.io/[OpenTelemetry] please refer to link:../opentelemetry/README.adoc[the dedicated example] + +There are 3 services which communicate each other, starting from the `random` service: + +- random: the main service, exposes the entry point REST service and store the results +- even: the service that verifies the even numbers +- odd: the service that verifies the odd numbers + +moreover there is a common module containing common classes + +image::docs/overview.png[] + +=== Build + +You can build this example using the following command; it will also download the OpenTelemetry agent used to instrument the applications: + + $ mvn package -Potel-agent + +=== Run + +Run docker-compose to start all the needed services: + + $ docker-compose -f containers/docker-compose.yml up -d + +the command runs: + +- https://github.com/minio/minio[minio] as application storage +- https://github.com/open-telemetry/opentelemetry-collector[opentelemetry-collector] to receive the generated Trace/Span +- https://github.com/jaegertracing/jaeger[Jaeger] to visualize the traces + +Run each services on separated terminals: + + $ source containers/env.sh \ + && java -javaagent:target/opentelemetry-javaagent.jar \ + -Dotel.service.name=random \ + -jar rest-cxf-otel-random/target/*.jar + + $ source containers/env.sh \ + && java -javaagent:target/opentelemetry-javaagent.jar \ + -Dotel.service.name=even \ + -Dserver.port=8081 \ + -jar rest-cxf-otel-even/target/*.jar + + $ source containers/env.sh \ + && java -javaagent:target/opentelemetry-javaagent.jar \ + -Dotel.service.name=odd \ + -Dserver.port=8082 \ + -jar rest-cxf-otel-odd/target/*.jar + +After the Spring Boot applications have been started, you can open the following URL in your web browser http://localhost:8080/services/ to access the list of services, including WADL definition + +You can also access the REST endpoint from the command line: + +i.e. to generate 5 random numbers run: + + $ curl -X POST http://localhost:8080/services/api/play/5 -s | jq . + +The command will produce an output like: + +[source,json] +---- +{ + "result": { + "ODD": [ + { + "number": 229, + "type": "ODD" + }, + { + "number": 585, + "type": "ODD" + } + ], + "EVEN": [ + { + "number": 648, + "type": "EVEN" + }, + { + "number": 670, + "type": "EVEN" + }, + { + "number": 846, + "type": "EVEN" + } + ] + }, + "evenCount": 3, + "oddCount": 2 +} +---- + +Now in the Jaeger UI http://localhost:16686 the traces will be available, both from Camel and from CXF instrumentation + +image::docs/jaeger.png[] + +The services can be stopped pressing `[CTRL] + [C]` in the shell, and the containers can be stopped with + + $ docker-compose -f containers/docker-compose.yml down + +=== Explain the code + +The dependency `org.apache.cxf:cxf-integration-tracing-opentelemetry` provides `org.apache.cxf.tracing.opentelemetry.jaxrs.OpenTelemetryFeature` that instruments the OpenTelemetry API implemented in the java agent. + +The feature is injected in the Spring context + +[source,java] +---- +include::rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/CxfConfig.java[lines=35..38] +---- + +and then it is configured in the Camel route as provider in the `cxfrs` endpoint + +[source,java] +---- +include::rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java[lines=51] +---- + +When the feature is enabled it is possible to add custom tags or logs using `TracerContext` from CXF +[source,java] +---- +include::rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomService.java[lines=56..58] +---- + +[source,java] +---- +include::rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomServiceImpl.java[lines=43..45] +---- + +=== Help and contributions + +If you hit any problem using Camel or have some feedback, then please +https://camel.apache.org/community/support/[let us know]. + +We also love contributors, so +https://camel.apache.org/community/contributing/[get involved] :-) + +The Camel riders! diff --git a/rest-cxf-opentelemetry/containers/docker-compose.yml b/rest-cxf-opentelemetry/containers/docker-compose.yml new file mode 100644 index 00000000..25b7e9d5 --- /dev/null +++ b/rest-cxf-opentelemetry/containers/docker-compose.yml @@ -0,0 +1,35 @@ +version: "3.9" + +services: + + minio: + image: "quay.io/minio/minio:latest" + environment: + - MINIO_ROOT_USER=admin + - MINIO_ROOT_PASSWORD=admin123 + ports: + - "9000:9000" + - "9001:9001" + command: + - server + - /data + - --console-address + - :9001 + + otel-collector: + image: otel/opentelemetry-collector:latest + command: + - --config=/etc/otelcol-cont/otel-collector.yml + volumes: + - ./otel-collector.yml:/etc/otelcol-cont/otel-collector.yml + ports: + - "4318:4318" # OTLP http receiver + - "4317:4317" # OTLP grpc receiver + depends_on: + - jaeger-all-in-one + + jaeger-all-in-one: + image: quay.io/jaegertracing/all-in-one:latest + restart: always + ports: + - "16686:16686" diff --git a/rest-cxf-opentelemetry/containers/env.sh b/rest-cxf-opentelemetry/containers/env.sh new file mode 100644 index 00000000..549fb238 --- /dev/null +++ b/rest-cxf-opentelemetry/containers/env.sh @@ -0,0 +1,8 @@ +#!/usr/bin/bash + +export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 +export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces +export OTEL_TRACES_EXPORTER=otlp +export OTEL_METRICS_EXPORTER=none +export OTEL_LOGS_EXPORTER=none +#export OTEL_JAVAAGENT_DEBUG=true diff --git a/rest-cxf-opentelemetry/containers/otel-collector.yml b/rest-cxf-opentelemetry/containers/otel-collector.yml new file mode 100644 index 00000000..db8a4beb --- /dev/null +++ b/rest-cxf-opentelemetry/containers/otel-collector.yml @@ -0,0 +1,25 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + +processors: + batch: + +exporters: + debug: + verbosity: detailed + otlp/jaeger: + endpoint: jaeger-all-in-one:4317 + tls: + insecure: true + +service: + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [debug,otlp/jaeger] diff --git a/rest-cxf-opentelemetry/docs/jaeger.png b/rest-cxf-opentelemetry/docs/jaeger.png new file mode 100644 index 00000000..e89e987d Binary files /dev/null and b/rest-cxf-opentelemetry/docs/jaeger.png differ diff --git a/rest-cxf-opentelemetry/docs/overview.png b/rest-cxf-opentelemetry/docs/overview.png new file mode 100644 index 00000000..15550cd6 Binary files /dev/null and b/rest-cxf-opentelemetry/docs/overview.png differ diff --git a/rest-cxf-opentelemetry/pom.xml b/rest-cxf-opentelemetry/pom.xml new file mode 100644 index 00000000..7d6adcdc --- /dev/null +++ b/rest-cxf-opentelemetry/pom.xml @@ -0,0 +1,163 @@ + + + 4.0.0 + + + org.apache.camel.springboot.example + examples + 4.8.0-SNAPSHOT + + + camel-example-spring-boot-rest-cxf-opentelemetry + Camel SB Examples :: REST using CXF and OpenTelemetry + An example showing Camel REST using CXF and OpenTelemetry with Spring Boot + pom + + + CXF + 2.7.0 + + + + rest-cxf-otel-common + rest-cxf-otel-random + rest-cxf-otel-even + rest-cxf-otel-odd + + + + + + + org.apache.camel.springboot + camel-spring-boot-bom + ${project.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot-version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.apache.camel.springboot + camel-direct-starter + + + org.apache.camel.springboot + camel-log-starter + + + org.apache.camel.springboot + camel-bean-starter + + + org.apache.camel.springboot + camel-bean-validator-starter + + + org.apache.camel.springboot + camel-cxf-rest-starter + + + org.apache.camel.springboot + camel-jackson-starter + + + + + org.apache.camel.springboot + camel-opentelemetry-starter + + + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-json-provider + + + + + org.apache.cxf + cxf-integration-tracing-opentelemetry + ${cxf-version} + + + + + org.apache.cxf + cxf-rt-rs-service-description + ${cxf-version} + + + + + + + otel-agent + + false + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + copy + + process-resources + + true + + + io.opentelemetry.javaagent + opentelemetry-javaagent + ${opentelemetry-javaagent.version} + jar + ${project.build.directory} + + + + + + + + + + + + diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/pom.xml b/rest-cxf-opentelemetry/rest-cxf-otel-common/pom.xml new file mode 100644 index 00000000..e5995f46 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/pom.xml @@ -0,0 +1,78 @@ + + + + + 4.0.0 + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-opentelemetry + 4.8.0-SNAPSHOT + + + camel-example-spring-boot-rest-cxf-otel-common + Camel SB Examples :: REST using CXF and OpenTelemetry :: Common + + + CXF + + + + + + org.apache.camel + camel-component-maven-plugin + ${camel-version} + + + generate + + generate + + process-classes + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + initialize + + add-source + add-resource + + + + src/generated/java + + + + src/generated/resources + + + + + + + + + diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/java/org/apache/camel/example/springboot/cxf/otel/InputStreamConverterLoader.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/java/org/apache/camel/example/springboot/cxf/otel/InputStreamConverterLoader.java new file mode 100644 index 00000000..daab67b2 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/java/org/apache/camel/example/springboot/cxf/otel/InputStreamConverterLoader.java @@ -0,0 +1,54 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.example.springboot.cxf.otel; + +import javax.annotation.processing.Generated; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.DeferredContextBinding; +import org.apache.camel.Exchange; +import org.apache.camel.TypeConversionException; +import org.apache.camel.TypeConverterLoaderException; +import org.apache.camel.spi.TypeConverterLoader; +import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.camel.support.SimpleTypeConverter; +import org.apache.camel.support.TypeConverterSupport; +import org.apache.camel.util.DoubleMap; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.TypeConverterLoaderGeneratorMojo") +@SuppressWarnings("unchecked") +@DeferredContextBinding +public final class InputStreamConverterLoader implements TypeConverterLoader, CamelContextAware { + + private CamelContext camelContext; + + public InputStreamConverterLoader() { + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException { + registerConverters(registry); + } + + private void registerConverters(TypeConverterRegistry registry) { + addTypeConverter(registry, org.apache.camel.example.springboot.cxf.otel.RandomNumber.class, java.io.InputStream.class, false, + (type, exchange, value) -> org.apache.camel.example.springboot.cxf.otel.InputStreamConverter.toRandomNumber((java.io.InputStream) value)); + } + + private static void addTypeConverter(TypeConverterRegistry registry, Class toType, Class fromType, boolean allowNull, SimpleTypeConverter.ConversionMethod method) { + registry.addTypeConverter(toType, fromType, new SimpleTypeConverter(allowNull, method)); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/java/org/apache/camel/example/springboot/cxf/otel/IntegerConverterLoader.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/java/org/apache/camel/example/springboot/cxf/otel/IntegerConverterLoader.java new file mode 100644 index 00000000..fe86ec1e --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/java/org/apache/camel/example/springboot/cxf/otel/IntegerConverterLoader.java @@ -0,0 +1,54 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.example.springboot.cxf.otel; + +import javax.annotation.processing.Generated; + +import org.apache.camel.CamelContext; +import org.apache.camel.CamelContextAware; +import org.apache.camel.DeferredContextBinding; +import org.apache.camel.Exchange; +import org.apache.camel.TypeConversionException; +import org.apache.camel.TypeConverterLoaderException; +import org.apache.camel.spi.TypeConverterLoader; +import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.camel.support.SimpleTypeConverter; +import org.apache.camel.support.TypeConverterSupport; +import org.apache.camel.util.DoubleMap; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@Generated("org.apache.camel.maven.packaging.TypeConverterLoaderGeneratorMojo") +@SuppressWarnings("unchecked") +@DeferredContextBinding +public final class IntegerConverterLoader implements TypeConverterLoader, CamelContextAware { + + private CamelContext camelContext; + + public IntegerConverterLoader() { + } + + @Override + public void setCamelContext(CamelContext camelContext) { + this.camelContext = camelContext; + } + + @Override + public CamelContext getCamelContext() { + return camelContext; + } + + @Override + public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException { + registerConverters(registry); + } + + private void registerConverters(TypeConverterRegistry registry) { + addTypeConverter(registry, org.apache.camel.example.springboot.cxf.otel.RandomNumber.class, java.lang.Integer.class, false, + (type, exchange, value) -> org.apache.camel.example.springboot.cxf.otel.IntegerConverter.toRandomNumber((java.lang.Integer) value)); + } + + private static void addTypeConverter(TypeConverterRegistry registry, Class toType, Class fromType, boolean allowNull, SimpleTypeConverter.ConversionMethod method) { + registry.addTypeConverter(toType, fromType, new SimpleTypeConverter(allowNull, method)); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader new file mode 100644 index 00000000..b01c01ee --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader @@ -0,0 +1,3 @@ +# Generated by camel build tools - do NOT edit this file! +org.apache.camel.example.springboot.cxf.otel.InputStreamConverterLoader +org.apache.camel.example.springboot.cxf.otel.IntegerConverterLoader diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/Constants.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/Constants.java new file mode 100644 index 00000000..00401086 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/Constants.java @@ -0,0 +1,30 @@ +/* + * 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.example.springboot.cxf.otel; + +public final class Constants { + + private Constants() { + } + + public static final String SERVICE_HEADER_NAME = "service-name"; + + public enum NUM_TYPE { + EVEN, + ODD + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/CxfConfig.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/CxfConfig.java new file mode 100644 index 00000000..d1a1751d --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/CxfConfig.java @@ -0,0 +1,39 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.cxf.tracing.opentelemetry.jaxrs.OpenTelemetryFeature; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider; + +@Configuration +public class CxfConfig { + + @Bean + public JacksonJsonProvider jaxrsProvider() { + return new JacksonJsonProvider().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + } + + @Bean + public OpenTelemetryFeature openTelemetryProvider() { + return new OpenTelemetryFeature(); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/InputStreamConverter.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/InputStreamConverter.java new file mode 100644 index 00000000..d5137d6d --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/InputStreamConverter.java @@ -0,0 +1,34 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.Converter; +import org.apache.camel.TypeConverters; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.io.InputStream; + +@Converter(generateLoader = true) +public class InputStreamConverter implements TypeConverters { + + @Converter + public static RandomNumber toRandomNumber(InputStream inputStream) throws IOException { + return new ObjectMapper().readValue(inputStream, RandomNumber.class); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/IntegerConverter.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/IntegerConverter.java new file mode 100644 index 00000000..ac5e361c --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/IntegerConverter.java @@ -0,0 +1,29 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.Converter; +import org.apache.camel.TypeConverters; + +@Converter(generateLoader = true) +public class IntegerConverter implements TypeConverters { + + @Converter + public static RandomNumber toRandomNumber(Integer num) { + return new RandomNumber(num); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomNumber.java b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomNumber.java new file mode 100644 index 00000000..c258f2f0 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-common/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomNumber.java @@ -0,0 +1,73 @@ +/* + * 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.example.springboot.cxf.otel; + +import java.util.Objects; +import java.util.Optional; + +import jakarta.validation.constraints.NotNull; + +public class RandomNumber { + + @NotNull + Integer number; + + Constants.NUM_TYPE type; + + public RandomNumber() { + } + + public RandomNumber(final Integer number) { + this.number = number; + } + + public Integer getNumber() { + return number; + } + + public RandomNumber setNumber(final Integer number) { + this.number = number; + return this; + } + + public Constants.NUM_TYPE getType() { + return type; + } + + public RandomNumber setType(final Constants.NUM_TYPE type) { + this.type = type; + return this; + } + + @Override + public String toString() { + return Optional.ofNullable(number).map(Objects::toString).orElse(""); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final RandomNumber that = (RandomNumber) o; + return Objects.equals(getNumber(), that.getNumber()); + } + + @Override + public int hashCode() { + return Objects.hash(getNumber()); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-even/pom.xml b/rest-cxf-opentelemetry/rest-cxf-otel-even/pom.xml new file mode 100644 index 00000000..f80eac93 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-even/pom.xml @@ -0,0 +1,63 @@ + + + + + 4.0.0 + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-opentelemetry + 4.8.0-SNAPSHOT + + + camel-example-spring-boot-rest-cxf-otel-even + Camel SB Examples :: REST using CXF and OpenTelemetry :: Even + + + CXF + + + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-otel-common + ${project.version} + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot-version} + + + + repackage + + + + + + + + diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java new file mode 100644 index 00000000..15b7d453 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java @@ -0,0 +1,37 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.opentelemetry.starter.CamelOpenTelemetry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +// CHECKSTYLE:OFF +@SpringBootApplication +@CamelOpenTelemetry +public class Application { + + /** + * Main method to start the application. + */ + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +// CHECKSTYLE:ON diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java new file mode 100644 index 00000000..c2aa5675 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java @@ -0,0 +1,63 @@ +/* + * 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.example.springboot.cxf.otel; + +import static org.apache.camel.example.springboot.cxf.otel.Constants.SERVICE_HEADER_NAME; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.bean.validator.BeanValidationException; +import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.apache.camel.model.dataformat.JsonLibrary; + +import org.springframework.stereotype.Component; + +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +@Component +public class CamelRouter extends RouteBuilder { + + @Override + public void configure() throws Exception { + //very raw way, just to handle the validation responses + onException(BeanValidationException.class) + .handled(true) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.BAD_REQUEST.getStatusCode())) + .setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}")); + + // @formatter:off + from("cxfrs:/api?" + + "resourceClasses=org.apache.camel.example.springboot.cxf.otel.EvenService" + + "&bindingStyle=SimpleConsumer" + + "&providers=jaxrsProvider,openTelemetryProvider" + + "&loggingFeatureEnabled=true") + .to("log:camel-cxf-log?showAll=true") + .setHeader(Exchange.BEAN_METHOD_NAME, simple("${header.operationName}")) + .bean(EvenServiceImpl.class); + + + from("direct:register").routeId("even-register") + .marshal().json(JsonLibrary.Jackson) + .setHeader(CxfConstants.HTTP_METHOD, constant("PUT")) + .setHeader(CxfConstants.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON)) + .setHeader(SERVICE_HEADER_NAME, constant("even")) + .toD("cxfrs:{{service.random.url}}/services/api/register"); + // @formatter:on + } + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/EvenService.java b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/EvenService.java new file mode 100644 index 00000000..bf0a62db --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/EvenService.java @@ -0,0 +1,43 @@ +/* + * 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.example.springboot.cxf.otel; + +import jakarta.validation.Valid; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +/** + * Service interface for managing users. + */ +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface EvenService { + + /** + * Check if the number is even, and eventually, register it + * + * @param number + * the number to verify + */ + @POST + @Path("/check") + RandomNumber check(@Valid RandomNumber number); + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/EvenServiceImpl.java b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/EvenServiceImpl.java new file mode 100644 index 00000000..446bf593 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/java/org/apache/camel/example/springboot/cxf/otel/EvenServiceImpl.java @@ -0,0 +1,42 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.ProducerTemplate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class EvenServiceImpl implements EvenService { + + private static final Logger LOGGER = LoggerFactory.getLogger(EvenServiceImpl.class); + + @Autowired + ProducerTemplate producerTemplate; + + @Override + public RandomNumber check(RandomNumber number) { + if (number.getNumber() % 2 == 0) { + //register + producerTemplate.sendBody("direct:register", new RandomNumber().setNumber(number.getNumber()).setType(Constants.NUM_TYPE.EVEN)); + } else { + LOGGER.info("skip {}, it is odd", number); + } + return number; + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/resources/application.properties b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/resources/application.properties new file mode 100644 index 00000000..4e64700f --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-even/src/main/resources/application.properties @@ -0,0 +1,22 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# the name of Camel +camel.springboot.name = cxf-otel-even +camel.springboot.main-run-controller=true +service.random.url = http://localhost:8080 +#logging.level.org.apache.cxf = TRACE diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-odd/pom.xml b/rest-cxf-opentelemetry/rest-cxf-otel-odd/pom.xml new file mode 100644 index 00000000..83fb364f --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-odd/pom.xml @@ -0,0 +1,63 @@ + + + + + 4.0.0 + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-opentelemetry + 4.8.0-SNAPSHOT + + + camel-example-spring-boot-rest-cxf-otel-odd + Camel SB Examples :: REST using CXF and OpenTelemetry :: Odd + + + CXF + + + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-otel-common + ${project.version} + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot-version} + + + + repackage + + + + + + + + diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java new file mode 100644 index 00000000..15b7d453 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java @@ -0,0 +1,37 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.opentelemetry.starter.CamelOpenTelemetry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +// CHECKSTYLE:OFF +@SpringBootApplication +@CamelOpenTelemetry +public class Application { + + /** + * Main method to start the application. + */ + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +// CHECKSTYLE:ON diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java new file mode 100644 index 00000000..d355dc00 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java @@ -0,0 +1,63 @@ +/* + * 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.example.springboot.cxf.otel; + +import static org.apache.camel.example.springboot.cxf.otel.Constants.SERVICE_HEADER_NAME; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.bean.validator.BeanValidationException; +import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.apache.camel.model.dataformat.JsonLibrary; + +import org.springframework.stereotype.Component; + +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +@Component +public class CamelRouter extends RouteBuilder { + + @Override + public void configure() throws Exception { + //very raw way, just to handle the validation responses + onException(BeanValidationException.class) + .handled(true) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.BAD_REQUEST.getStatusCode())) + .setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}")); + + // @formatter:off + from("cxfrs:/api?" + + "resourceClasses=org.apache.camel.example.springboot.cxf.otel.OddService" + + "&bindingStyle=SimpleConsumer" + + "&providers=jaxrsProvider,openTelemetryProvider" + + "&loggingFeatureEnabled=true") + .to("log:camel-cxf-log?showAll=true") + .setHeader(Exchange.BEAN_METHOD_NAME, simple("${header.operationName}")) + .bean(OddServiceImpl.class); + + + from("direct:register").routeId("odd-register") + .marshal().json(JsonLibrary.Jackson) + .setHeader(CxfConstants.HTTP_METHOD, constant("PUT")) + .setHeader(CxfConstants.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON)) + .setHeader(SERVICE_HEADER_NAME, constant("odd")) + .toD("cxfrs:{{service.random.url}}/services/api/register"); + // @formatter:on + } + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/OddService.java b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/OddService.java new file mode 100644 index 00000000..4ecdce5e --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/OddService.java @@ -0,0 +1,43 @@ +/* + * 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.example.springboot.cxf.otel; + +import jakarta.validation.Valid; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +/** + * Service interface for managing users. + */ +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface OddService { + + /** + * Check if the number is odd, and eventually, register it + * + * @param number + * the number to verify + */ + @POST + @Path("/check") + RandomNumber check(@Valid RandomNumber number); + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/OddServiceImpl.java b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/OddServiceImpl.java new file mode 100644 index 00000000..bab2b46d --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/java/org/apache/camel/example/springboot/cxf/otel/OddServiceImpl.java @@ -0,0 +1,42 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.ProducerTemplate; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class OddServiceImpl implements OddService { + + private static final Logger LOGGER = LoggerFactory.getLogger(OddServiceImpl.class); + + @Autowired + ProducerTemplate producerTemplate; + + @Override + public RandomNumber check(RandomNumber number) { + if (number.getNumber() % 2 == 1) { + //register + producerTemplate.sendBody("direct:register", new RandomNumber().setNumber(number.getNumber()).setType(Constants.NUM_TYPE.ODD)); + } else { + LOGGER.info("skip {}, it is even", number); + } + return number; + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/resources/application.properties b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/resources/application.properties new file mode 100644 index 00000000..0a6755a3 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-odd/src/main/resources/application.properties @@ -0,0 +1,22 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# the name of Camel +camel.springboot.name = cxf-otel-odd +camel.springboot.main-run-controller=true +service.random.url = http://localhost:8080 +#logging.level.org.apache.cxf = TRACE diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/pom.xml b/rest-cxf-opentelemetry/rest-cxf-otel-random/pom.xml new file mode 100644 index 00000000..ed984b9f --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/pom.xml @@ -0,0 +1,67 @@ + + + + + 4.0.0 + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-opentelemetry + 4.8.0-SNAPSHOT + + + camel-example-spring-boot-rest-cxf-otel-random + Camel SB Examples :: REST using CXF and OpenTelemetry :: Random + + + CXF + + + + + org.apache.camel.springboot.example + camel-example-spring-boot-rest-cxf-otel-common + ${project.version} + + + + org.apache.camel.springboot + camel-minio-starter + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot-version} + + + + repackage + + + + + + + + diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java new file mode 100644 index 00000000..15b7d453 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/Application.java @@ -0,0 +1,37 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.opentelemetry.starter.CamelOpenTelemetry; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +// CHECKSTYLE:OFF +@SpringBootApplication +@CamelOpenTelemetry +public class Application { + + /** + * Main method to start the application. + */ + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +// CHECKSTYLE:ON diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java new file mode 100644 index 00000000..9d7e9c4f --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/CamelRouter.java @@ -0,0 +1,131 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.bean.validator.BeanValidationException; +import org.apache.camel.component.cxf.common.message.CxfConstants; +import org.apache.camel.component.minio.MinioConstants; +import org.apache.camel.model.dataformat.JsonLibrary; + +import org.springframework.stereotype.Component; + +import java.security.SecureRandom; + +import io.minio.Result; +import io.minio.messages.Contents; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + +@Component +public class CamelRouter extends RouteBuilder { + + + @Override + public void configure() throws Exception { + //very raw way, just to handle the validation responses + onException(BeanValidationException.class) + .handled(true) + .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.BAD_REQUEST.getStatusCode())) + .setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}")); + + // @formatter:off + from("cxfrs:/api?" + + "resourceClasses=org.apache.camel.example.springboot.cxf.otel.RandomService" + + "&bindingStyle=SimpleConsumer" + + "&providers=jaxrsProvider,openTelemetryProvider" + + "&loggingFeatureEnabled=true") + .to("log:camel-cxf-log?showAll=true") + .setHeader(Exchange.BEAN_METHOD_NAME, simple("${header.operationName}")) + .bean(RandomServiceImpl.class); + + + from("direct:play").routeId("play") + .loop(header("attempts")) + .process(exchange -> exchange.getIn().getHeaders().clear()) + .setHeader(CxfConstants.HTTP_METHOD, constant("GET")) + .toD("cxfrs:{{service.random.url}}/services/api/generate") + .process(exchange -> exchange.getIn().getHeaders().clear()) + .setHeader(CxfConstants.HTTP_METHOD, constant("POST")) + .setHeader(CxfConstants.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON)) + .toD("cxfrs:{{service.even.url}}/services/api/check") + .process(exchange -> exchange.getIn().getHeaders().clear()) + .setHeader(CxfConstants.HTTP_METHOD, constant("POST")) + .setHeader(CxfConstants.CONTENT_TYPE, constant(MediaType.APPLICATION_JSON)) + .toD("cxfrs:{{service.odd.url}}/services/api/check") + .end() + .setBody(constant(null)); + + from("direct:random").routeId("generate-random") + .loadBalance().random() + .to("direct:generate-even") + .to("direct:generate-odd") + .end() + .convertBodyTo(RandomNumber.class); + + from("direct:generate-even") + .routeId("generate-even") + .process(exchange -> { + int num = random(); + while (num % 2 != 0) { + num = random(); + } + exchange.getIn().setBody(num); + }); + + from("direct:generate-odd").routeId("generate-odd") + .process(exchange -> { + int num = random(); + while (num % 2 == 0) { + num = random(); + } + exchange.getIn().setBody(num); + }); + + from("direct:save-obj").routeId("save-obj") + .setHeader(MinioConstants.OBJECT_NAME, header("objectName")) + .marshal().json(JsonLibrary.Jackson) + .toD("minio://{{bucket.name}}"); + + from("direct:load-results").routeId("load-results") + .setVariable("results", () -> new Results()) + .toD("minio://{{bucket.name}}?operation=listObjects") + .split(body()) + .process(exchange -> { + try { + exchange.getIn().setHeader(MinioConstants.OBJECT_NAME + , ((Contents) exchange.getIn().getBody(Result.class).get()).objectName()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }) + .toD("minio://{{bucket.name}}?operation=getObject") + .unmarshal().json(JsonLibrary.Jackson, RandomNumber.class) + .process(exchange -> exchange.getVariable("results", Results.class) + .addNumber(exchange.getIn().getBody(RandomNumber.class))) + .end() + .setBody(variable("results")); + // @formatter:on + + } + + private static int random() { + return new SecureRandom().nextInt(100, 1000); + } + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomService.java b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomService.java new file mode 100644 index 00000000..fd2e23b3 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomService.java @@ -0,0 +1,71 @@ +/* + * 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.example.springboot.cxf.otel; + +import org.apache.camel.Exchange; +import org.apache.cxf.tracing.TracerContext; + +import jakarta.validation.Valid; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.PUT; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; + +/** + * Service interface for managing users. + */ +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +public interface RandomService { + + /** + * Find a user by the given ID + * + * @param attempts + * the number of attempts, how many random numbers will be generated + * @return Results, the results + */ + @POST + @Path("/play/{attempts}") + Results play(@PathParam("attempts") Integer attempts); + + /** + * Generate random number between 100 and 1000 + * + * @return RandomNumber, the number + */ + @GET + @Path("/generate") + RandomNumber generate(@Context TracerContext tracer); + + /** + * Register result + * + * @param number + * the number to register + * + */ + @PUT + @Path("/register") + void register(@Valid RandomNumber number, Exchange exchange); + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomServiceImpl.java b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomServiceImpl.java new file mode 100644 index 00000000..1941b0aa --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/RandomServiceImpl.java @@ -0,0 +1,59 @@ +/* + * 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.example.springboot.cxf.otel; + +import static org.apache.camel.example.springboot.cxf.otel.Constants.SERVICE_HEADER_NAME; + +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.cxf.tracing.TracerContext; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +public class RandomServiceImpl implements RandomService { + + private static final Logger LOGGER = LoggerFactory.getLogger(RandomServiceImpl.class); + + @Autowired + ProducerTemplate producerTemplate; + + @Override + public Results play(Integer attempts) { + producerTemplate.requestBodyAndHeader("direct:play", null, "attempts", attempts, Void.class); + return producerTemplate.requestBody("direct:load-results", null, Results.class); + } + + @Override + public RandomNumber generate(final TracerContext tracer) { + tracer.timeline("generate number"); + tracer.annotate("custom-op", "generate"); + return producerTemplate.requestBody("direct:random", null, RandomNumber.class); + } + + @Override + public void register(RandomNumber number, Exchange exchange) { + final String serviceName = (String) exchange.getIn().getHeader(SERVICE_HEADER_NAME); + assert serviceName != null; + assert number != null; + assert number.getType() != null; + LOGGER.info("register {}", number); + final String objName = String.format("%s-%s", serviceName, number.getNumber()); + producerTemplate.sendBodyAndHeader("direct:save-obj", number, "objectName", objName); + } +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/Results.java b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/Results.java new file mode 100644 index 00000000..ba0d7e56 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/java/org/apache/camel/example/springboot/cxf/otel/Results.java @@ -0,0 +1,62 @@ +/* + * 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.example.springboot.cxf.otel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import jakarta.validation.constraints.NotNull; + +public class Results { + @NotNull + Map> result; + + public Results() { + result = new ConcurrentHashMap<>(2); + } + + public Map> getResult() { + return result; + } + + public int getEvenCount() { + return count(Constants.NUM_TYPE.EVEN); + } + + public int getOddCount() { + return count(Constants.NUM_TYPE.ODD); + } + + public Results addNumber(RandomNumber num) { + addNumber(num.getType(), num); + return this; + } + + private void addNumber(Constants.NUM_TYPE evenOddKey, RandomNumber number) { + final List values = Optional.ofNullable(result.get(evenOddKey)).orElseGet(() -> new ArrayList<>()); + values.add(number); + result.put(evenOddKey, values); + } + + private Integer count(Constants.NUM_TYPE key) { + return Optional.ofNullable(result.get(key)).map(List::size).orElse(0); + } + +} diff --git a/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/resources/application.properties b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/resources/application.properties new file mode 100644 index 00000000..dd013fa9 --- /dev/null +++ b/rest-cxf-opentelemetry/rest-cxf-otel-random/src/main/resources/application.properties @@ -0,0 +1,28 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# the name of Camel +camel.springboot.name = cxf-otel-random +camel.springboot.main-run-controller=true +service.random.url = http://localhost:8080 +service.even.url = http://localhost:8081 +service.odd.url = http://localhost:8082 +bucket.name = evenodd +camel.component.minio.access-key = admin +camel.component.minio.secret-key = admin123 +camel.component.minio.endpoint = http://localhost:9000 +#logging.level.org.apache.cxf = TRACE