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-examples.git
commit 8c084eead8f06b96c76b3d38e112910dcbf325f1 Author: JiriOndrusek <[email protected]> AuthorDate: Fri Mar 20 16:30:14 2026 +0100 Add Quarkus based REST Jackson example --- docs/modules/ROOT/attachments/examples.json | 5 + quarkus-rest-json/README.adoc | 131 ++++++++ quarkus-rest-json/eclipse-formatter-config.xml | 276 +++++++++++++++++ quarkus-rest-json/pom.xml | 328 +++++++++++++++++++++ .../acme/rest/json/camel/OrderMessagingRoute.java | 79 +++++ .../acme/rest/json/camel/OrderProcessingRoute.java | 65 ++++ .../acme/rest/json/common/model/ErrorResponse.java | 67 +++++ .../org/acme/rest/json/common/model/Order.java | 100 +++++++ .../org/acme/rest/json/common/model/OrderItem.java | 105 +++++++ .../acme/rest/json/common/model/OrderResponse.java | 98 ++++++ .../json/common/processing/PriceCalculator.java | 81 +++++ .../common/processing/ProcessedOrdersRegistry.java | 53 ++++ .../org/acme/rest/json/quarkus/OrderResource.java | 87 ++++++ .../src/main/resources/application.properties | 101 +++++++ .../java/org/acme/rest/json/OrderResoourceIT.java | 25 ++ .../java/org/acme/rest/json/OrderResourceTest.java | 166 +++++++++++ quarkus-rest-json/test-requests.sh | 112 +++++++ 17 files changed, 1879 insertions(+) diff --git a/docs/modules/ROOT/attachments/examples.json b/docs/modules/ROOT/attachments/examples.json index 0969b2b8..c755be4c 100644 --- a/docs/modules/ROOT/attachments/examples.json +++ b/docs/modules/ROOT/attachments/examples.json @@ -109,6 +109,11 @@ "description": "Demonstrates how to create a REST service using the Camel REST DSL and Jackson.", "link": "https://github.com/apache/camel-quarkus-examples/tree/main/rest-json" }, + { + "title": "REST with Jackson: A Quarkus based example", + "description": "Demonstrates how to use REST (Jackson) endpoints from a Quarkus project and invoke Camel routes.", + "link": "https://github.com/apache/camel-quarkus-examples/tree/main/quarkus-rest-json" + }, { "title": "Saga and LRA", "description": "Shows how to use saga and lra", diff --git a/quarkus-rest-json/README.adoc b/quarkus-rest-json/README.adoc new file mode 100644 index 00000000..c06c5696 --- /dev/null +++ b/quarkus-rest-json/README.adoc @@ -0,0 +1,131 @@ += REST with Jackson: A Quarkus based example +:cq-example-description: An example that demonstrates how to use REST (Jackson) endpoints from a Quarkus project and invoke Camel routes. + +{cq-description} + +This example demonstrates how to invoke Camel routes from REST endpoints defined in a Quarkus project. + +TIP: Check the https://camel.apache.org/camel-quarkus/latest/first-steps.html[Camel Quarkus User guide] for prerequisites +and other general information. + +== Prerequisites + +The example application requires a Kafka instance. + +You do not need to provide a Kafka instance manually when running in development mode (`mvn quarkus:dev` - read more https://quarkus.io/guides/getting-started#development-mode[here]) or when executing the supplied tests (`mvn test`). +In these scenarios, Quarkus automatically provisions a Strimzi container via https://quarkus.io/guides/kafka-dev-services[Quarkus Dev Services] and configures the application accordingly, requiring no changes to `application.properties`. + +== Start in the Development mode + +[source,shell] +---- +$ mvn clean compile quarkus:dev +---- + +The above command compiles the project, starts the application, and enables live reload via Quarkus tooling. +Any modifications to your project will be automatically hot-reloaded into the running application. + +TIP: Please refer to the Development mode section of +https://camel.apache.org/camel-quarkus/latest/first-steps.html#_development_mode[Camel Quarkus User guide] for more details. + +Then submit orders to the REST endpoint by running the `test-requests.sh` script + +or + +send requests directly to the REST endpoint at http://localhost:8080/api/orders. + +An example payload: +``` +{ + "customerId": "CUST001", + "items": [ + { + "productId": "PROD001", + "productName": "Widget A", + "quantity": 1, + "price": 50 + }, + { + "productId": "PROD002", + "productName": "Widget B", + "quantity": 2, + "price": 25 + } + ] + } +``` + +=== Configure Kafka client, package and run the application + +Once development is complete, you may want to configure the Kafka client, package the application, and run it in production mode. + +TIP: Find more details about the JVM mode and Native mode in the Package and run section of +https://camel.apache.org/camel-quarkus/latest/first-steps.html#_package_and_run_the_application[Camel Quarkus User guide] + +==== Configure kafka client + +Uncomment the appropriate section in `src/main/resources/application.properties` based on your authentication method: + +- *Kafka instance without Authentication* - if no authentication is required. +- *Kafka instance with SASL Plain* - if using SASL Plain authentication. +- *Kafka instance with SASL Oauth Bearer* - if using OAuth Bearer authentication. + +Set the corresponding environment variables: +- Without Authentication + +[source,shell] +---- +$ export brokers=<YOUR_KAFKA_BROKERS_URL> +---- +- SASL Plain +[source,shell] +---- +$ export brokers=<YOUR_KAFKA_BROKERS_URL> +$ export id=<YOUR_KAFKA_SASL_CLIENT_ID> +$ export secret=<YOUR_KAFKA_SASL_CLIENT_SECRET> +---- +- SASL Oauth Bearer +[source,shell] +---- +$ export brokers=<YOUR_KAFKA_BROKERS_URL> +$ export id=<YOUR_KAFKA_SASL_CLIENT_ID> +$ export secret=<YOUR_KAFKA_SASL_CLIENT_SECRET> +$ export token=<YOUR_KAFKA_SASL_OAUTHBEARER_TOKEN_URL> +---- + +To deploy on Kubernetes or OpenShift, define the above environment variables in a secret named `camel-kafka`. Configure the required values in `kubefiles/secret-example.yml`, then create the secret: + +[source,shell] +---- +$ kubectl apply -f kubefiles/secret-example.yml +---- + +==== JVM mode + +[source,shell] +---- +$ mvn clean package +$ java -jar target/quarkus-app/quarkus-run.jar +... +[io.quarkus] (main) camel-quarkus-examples-... started in 1.163s. Listening on: http://0.0.0.0:8080 +---- + +==== Native mode + +IMPORTANT: Native mode requires having GraalVM and other tools installed. Please check the Prerequisites section +of https://camel.apache.org/camel-quarkus/latest/first-steps.html#_prerequisites[Camel Quarkus User guide]. + +To prepare a native executable using GraalVM, run the following command: + +[source,shell] +---- +$ mvn clean package -Dnative +$ ./target/*-runner +... +[io.quarkus] (main) camel-quarkus-examples-... started in 0.013s. Listening on: http://0.0.0.0:8080 +... +---- + +== Feedback + +Please report bugs and propose improvements via https://github.com/apache/camel-quarkus/issues[GitHub issues of Camel Quarkus] project. diff --git a/quarkus-rest-json/eclipse-formatter-config.xml b/quarkus-rest-json/eclipse-formatter-config.xml new file mode 100644 index 00000000..2248b2b8 --- /dev/null +++ b/quarkus-rest-json/eclipse-formatter-config.xml @@ -0,0 +1,276 @@ +<?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. + +--> +<profiles version="8"> + <profile name="Camel Java Conventions" version="8" kind="CodeFormatterProfile"> + <setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/> + <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/> + <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_comments" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.indent_return_description" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/> + <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/> + <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/> + <setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.indentation.size" value="8"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/> + <setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="128"/> + <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/> + <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/> + <setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/> + <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/> + <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/> + <setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/> + <setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="CHECKSTYLE:OFF"/> + <setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="CHECKSTYLE:ON"/> + </profile> +</profiles> diff --git a/quarkus-rest-json/pom.xml b/quarkus-rest-json/pom.xml new file mode 100644 index 00000000..2264cc93 --- /dev/null +++ b/quarkus-rest-json/pom.xml @@ -0,0 +1,328 @@ +<?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> + + <artifactId>camel-quarkus-examples-rest-json</artifactId> + <groupId>org.apache.camel.quarkus.examples</groupId> + <version>3.33.0-SNAPSHOT</version> + + <name>Camel Quarkus :: Examples :: Quarkus Rest Json</name> + <description>Camel Quarkus Example :: Quarkus Rest Json</description> + + <properties> + <quarkus.platform.version>3.33.0</quarkus.platform.version> + <camel-quarkus.platform.version>3.33.0-SNAPSHOT</camel-quarkus.platform.version> + + <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id> + <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> + <camel-quarkus.platform.group-id>org.apache.camel.quarkus</camel-quarkus.platform.group-id> + <camel-quarkus.platform.artifact-id>camel-quarkus-bom</camel-quarkus.platform.artifact-id> + + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <maven.compiler.release>17</maven.compiler.release> + + <formatter-maven-plugin.version>2.29.0</formatter-maven-plugin.version> + <impsort-maven-plugin.version>1.13.0</impsort-maven-plugin.version> + <license-maven-plugin.version>5.0.0</license-maven-plugin.version> + <maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version> + <maven-jar-plugin.version>3.5.0</maven-jar-plugin.version> + <maven-resources-plugin.version>3.3.1</maven-resources-plugin.version> + <maven-surefire-plugin.version>3.5.5</maven-surefire-plugin.version> + </properties> + + <dependencyManagement> + <dependencies> + <!-- Import BOM --> + <dependency> + <groupId>${quarkus.platform.group-id}</groupId> + <artifactId>${quarkus.platform.artifact-id}</artifactId> + <version>${quarkus.platform.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <dependency> + <groupId>${camel-quarkus.platform.group-id}</groupId> + <artifactId>${camel-quarkus.platform.artifact-id}</artifactId> + <version>${camel-quarkus.platform.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + + <dependencies> + <!-- Quarkus Rest --> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-rest</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-rest-jackson</artifactId> + </dependency> + <!-- Camel Quarkus --> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-jackson</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-direct</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bean</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-kafka</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-hibernate-validator</artifactId> + </dependency> + + <!-- test dependencies --> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.rest-assured</groupId> + <artifactId>rest-assured</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <pluginManagement> + <plugins> + + <plugin> + <groupId>net.revelc.code.formatter</groupId> + <artifactId>formatter-maven-plugin</artifactId> + <version>${formatter-maven-plugin.version}</version> + <configuration> + <configFile>${maven.multiModuleProjectDirectory}/eclipse-formatter-config.xml</configFile> + <lineEnding>LF</lineEnding> + </configuration> + </plugin> + + <plugin> + <groupId>net.revelc.code</groupId> + <artifactId>impsort-maven-plugin</artifactId> + <version>${impsort-maven-plugin.version}</version> + <configuration> + <groups>java.,javax.,org.w3c.,org.xml.,junit.</groups> + <removeUnused>true</removeUnused> + <staticAfter>true</staticAfter> + <staticGroups>java.,javax.,org.w3c.,org.xml.,junit.</staticGroups> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin.version}</version> + <configuration> + <showDeprecation>true</showDeprecation> + <showWarnings>true</showWarnings> + <compilerArgs> + <arg>-Xlint:unchecked</arg> + </compilerArgs> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>${maven-surefire-plugin.version}</version> + <configuration> + <failIfNoTests>false</failIfNoTests> + <systemPropertyVariables> + <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager> + </systemPropertyVariables> + </configuration> + </plugin> + + <plugin> + <groupId>${quarkus.platform.group-id}</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <version>${quarkus.platform.version}</version> + <extensions>true</extensions> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <version>${maven-surefire-plugin.version}</version> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>${maven-jar-plugin.version}</version> + </plugin> + + <plugin> + <groupId>com.mycila</groupId> + <artifactId>license-maven-plugin</artifactId> + <version>${license-maven-plugin.version}</version> + <configuration> + <failIfUnknown>true</failIfUnknown> + <header>${maven.multiModuleProjectDirectory}/header.txt</header> + <excludes> + <exclude>**/*.adoc</exclude> + <exclude>**/*.txt</exclude> + <exclude>**/LICENSE.txt</exclude> + <exclude>**/LICENSE</exclude> + <exclude>**/NOTICE.txt</exclude> + <exclude>**/NOTICE</exclude> + <exclude>**/README</exclude> + <exclude>**/pom.xml.versionsBackup</exclude> + <exclude>**/quarkus.log*</exclude> + </excludes> + <mapping> + <java>SLASHSTAR_STYLE</java> + <properties>CAMEL_PROPERTIES_STYLE</properties> + <kt>SLASHSTAR_STYLE</kt> + </mapping> + <headerDefinitions> + <headerDefinition>${maven.multiModuleProjectDirectory}/license-properties-headerdefinition.xml</headerDefinition> + </headerDefinitions> + </configuration> + </plugin> + </plugins> + </pluginManagement> + + <plugins> + <plugin> + <groupId>${quarkus.platform.group-id}</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <executions> + <execution> + <id>build</id> + <goals> + <goal>build</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>net.revelc.code.formatter</groupId> + <artifactId>formatter-maven-plugin</artifactId> + <executions> + <execution> + <id>format</id> + <goals> + <goal>format</goal> + </goals> + <phase>process-sources</phase> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>net.revelc.code</groupId> + <artifactId>impsort-maven-plugin</artifactId> + <executions> + <execution> + <id>sort-imports</id> + <goals> + <goal>sort</goal> + </goals> + <phase>process-sources</phase> + </execution> + </executions> + </plugin> + + <plugin> + <groupId>com.mycila</groupId> + <artifactId>license-maven-plugin</artifactId> + <executions> + <execution> + <id>license-format</id> + <goals> + <goal>format</goal> + </goals> + <phase>process-sources</phase> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>native</id> + <activation> + <property> + <name>native</name> + </property> + </activation> + <properties> + <quarkus.native.enabled>true</quarkus.native.enabled> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + <configuration> + <systemPropertyVariables> + <quarkus.native.enabled>${quarkus.native.enabled}</quarkus.native.enabled> + </systemPropertyVariables> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>skip-testcontainers-tests</id> + <activation> + <property> + <name>skip-testcontainers-tests</name> + </property> + </activation> + <properties> + <skipTests>true</skipTests> + </properties> + </profile> + </profiles> + +</project> diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/camel/OrderMessagingRoute.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/camel/OrderMessagingRoute.java new file mode 100644 index 00000000..e39e7678 --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/camel/OrderMessagingRoute.java @@ -0,0 +1,79 @@ +/* + * 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.acme.rest.json.camel; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import org.acme.rest.json.common.model.Order; +import org.acme.rest.json.common.processing.ProcessedOrdersRegistry; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.kafka.KafkaConstants; +import org.apache.camel.model.dataformat.JsonLibrary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@ApplicationScoped +public class OrderMessagingRoute extends RouteBuilder { + + private static final Logger log = LoggerFactory.getLogger(OrderMessagingRoute.class); + + @Inject + ProcessedOrdersRegistry processedOrdersRegistry; + + @Override + public void configure() throws Exception { + + // Producer: Send order to Kafka with error handling + from("direct:sendToKafka") + .routeId("send-to-kafka") + .onException(Exception.class) + .log("ERROR: Failed to send message to Kafka: ${exception.message}") + .handled(true) + .end() + .setHeader(KafkaConstants.KEY, simple("${body.orderId}")) + .marshal().json(JsonLibrary.Jackson) + .to("kafka:{{kafka.topic.orders.requests}}") + .log("Message sent to Kafka topic! Order ID: ${header." + KafkaConstants.KEY + "}"); + + // Consumer: Process orders from Kafka with error handling + from("kafka:{{kafka.topic.orders.requests}}" + + "?groupId={{kafka.consumer.group.id}}" + + "&autoOffsetReset=earliest" + + "&keyDeserializer=org.apache.kafka.common.serialization.StringDeserializer" + + "&valueDeserializer=org.apache.kafka.common.serialization.StringDeserializer") + .routeId("kafka-order-consumer") + .onException(Exception.class) + .log("ERROR: Failed to process Kafka message: ${exception.message}") + .handled(true) + .end() + .log("Received from Kafka: \"${body}\"") + .unmarshal().json(JsonLibrary.Jackson, Order.class) + .delay(1000) // Simulate processing time + .process(exchange -> { + Order order = exchange.getIn().getBody(Order.class); + if (order == null) { + log.error("Received null order from Kafka"); + return; + } + log.info("✓ Order {} was processed via Kafka consumer for customer: {}", + order.getOrderId(), order.getCustomerId()); + + // Register order as processed (for testing verification) + processedOrdersRegistry.registerProcessed(order.getOrderId()); + }); + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/camel/OrderProcessingRoute.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/camel/OrderProcessingRoute.java new file mode 100644 index 00000000..756d7bcb --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/camel/OrderProcessingRoute.java @@ -0,0 +1,65 @@ +/* + * 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.acme.rest.json.camel; + +import jakarta.enterprise.context.ApplicationScoped; +import org.acme.rest.json.common.model.Order; +import org.acme.rest.json.common.model.OrderResponse; +import org.acme.rest.json.common.processing.PriceCalculator; +import org.apache.camel.builder.RouteBuilder; + +@ApplicationScoped +public class OrderProcessingRoute extends RouteBuilder { + + @Override + public void configure() throws Exception { + + // Main processing route - fire and forget + from("direct:processOrder") + .routeId("order-processing-main") + // Validate order is not null before processing + .validate(body().isNotNull()) + .validate(body().isInstanceOf(Order.class)) + .log("Processing order: ${body.orderId} for customer: ${body.customerId}") + + // Calculate pricing + .bean(PriceCalculator.class, "calculate") + .log("Price calculated: ${body.orderId}, total: ${body.totalAmount}") + + // Save Order before sending to Kafka (body will be marshaled to JSON) + .setProperty("originalOrder", body()) + + // Send to Kafka (fire-and-forget) + .to("direct:sendToKafka") + + // Prepare immediate response (don't wait for Kafka processing) + .process(exchange -> { + Order order = exchange.getProperty("originalOrder", Order.class); + // After validation, this should never be null, but keeping check for safety + if (order == null) { + throw new IllegalStateException("Order property is null - cannot create response"); + } + + OrderResponse response = OrderResponse.success( + order.getOrderId(), + order.getTotalAmount()); + exchange.getMessage().setBody(response); + }) + .log("Order sent to Kafka at: ${body.timestamp}"); + + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/ErrorResponse.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/ErrorResponse.java new file mode 100644 index 00000000..8039642e --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/ErrorResponse.java @@ -0,0 +1,67 @@ +/* + * 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.acme.rest.json.common.model; + +import java.time.LocalDateTime; + +import io.quarkus.runtime.annotations.RegisterForReflection; + +@RegisterForReflection +public class ErrorResponse { + + private String error; + private String orderId; + private LocalDateTime timestamp; + + public ErrorResponse() { + this.timestamp = LocalDateTime.now(); + } + + public ErrorResponse(String error, String orderId) { + this.error = error; + this.orderId = orderId; + this.timestamp = LocalDateTime.now(); + } + + public static ErrorResponse of(String error, String orderId) { + return new ErrorResponse(error, orderId); + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public LocalDateTime getTimestamp() { + return timestamp; + } + + public void setTimestamp(LocalDateTime timestamp) { + this.timestamp = timestamp; + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/Order.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/Order.java new file mode 100644 index 00000000..dbb23e31 --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/Order.java @@ -0,0 +1,100 @@ +/* + * 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.acme.rest.json.common.model; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; + +@RegisterForReflection +public class Order { + + private String orderId; + + @NotBlank(message = "Customer ID is required") + private String customerId; + + @NotEmpty(message = "Order must contain at least one item") + private List<OrderItem> items = new ArrayList<>(); + + private BigDecimal totalAmount; + + public Order() { + // UUID will be set in getter if not provided + } + + public String getOrderId() { + if (orderId == null) { + orderId = UUID.randomUUID().toString(); + } + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getCustomerId() { + return customerId; + } + + public void setCustomerId(String customerId) { + this.customerId = customerId; + } + + public BigDecimal getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(BigDecimal totalAmount) { + this.totalAmount = totalAmount; + } + + public List<OrderItem> getItems() { + return items; + } + + public void setItems(List<OrderItem> items) { + this.items = items; + } + + public BigDecimal calculateTotal() { + if (items == null || items.isEmpty()) { + return BigDecimal.ZERO; + } + return items.stream() + .filter(Objects::nonNull) + .map(OrderItem::getSubtotal) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + @Override + public String toString() { + return "Order{" + + "orderId='" + orderId + '\'' + + ", customerId='" + customerId + '\'' + + ", items=" + items + + ", totalAmount=" + totalAmount + + '}'; + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/OrderItem.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/OrderItem.java new file mode 100644 index 00000000..76670989 --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/OrderItem.java @@ -0,0 +1,105 @@ +/* + * 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.acme.rest.json.common.model; + +import java.math.BigDecimal; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +@RegisterForReflection +public class OrderItem { + + @NotBlank(message = "Product ID is required") + private String productId; + + @NotBlank(message = "Product name is required") + private String productName; + + @NotNull(message = "Quantity is required") + @Min(value = 1, message = "Quantity must be at least 1") + private Integer quantity; + + @NotNull(message = "Price is required") + @DecimalMin(value = "0.01", message = "Price must be greater than 0") + private BigDecimal price; + + public OrderItem() { + // No-arg constructor for Jackson deserialization + } + + public OrderItem(String productId, String productName, Integer quantity, BigDecimal price) { + this.productId = productId; + this.productName = productName; + this.quantity = quantity; + this.price = price; + } + + public String getProductId() { + return productId; + } + + public void setProductId(String productId) { + this.productId = productId; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + @JsonIgnore + public BigDecimal getSubtotal() { + if (price != null && quantity != null) { + return price.multiply(BigDecimal.valueOf(quantity)); + } + return BigDecimal.ZERO; + } + + @Override + public String toString() { + return "OrderItem{" + + "productId='" + productId + '\'' + + ", productName='" + productName + '\'' + + ", quantity=" + quantity + + ", price=" + price + + '}'; + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/OrderResponse.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/OrderResponse.java new file mode 100644 index 00000000..32fdd72f --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/model/OrderResponse.java @@ -0,0 +1,98 @@ +/* + * 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.acme.rest.json.common.model; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import io.quarkus.runtime.annotations.RegisterForReflection; + +@RegisterForReflection +public class OrderResponse { + + private String orderId; + private boolean confirmed; + private BigDecimal totalAmount; + private LocalDateTime timestamp; + + public OrderResponse() { + this.timestamp = LocalDateTime.now(); + } + + public OrderResponse(String orderId, boolean confirmed) { + this.orderId = orderId; + this.confirmed = confirmed; + this.timestamp = LocalDateTime.now(); + } + + public static OrderResponse success(String orderId, BigDecimal totalAmount) { + OrderResponse response = new OrderResponse(); + response.setOrderId(orderId); + response.setConfirmed(true); + response.setTotalAmount(totalAmount); + return response; + } + + public static OrderResponse error(String orderId) { + OrderResponse response = new OrderResponse(); + response.setOrderId(orderId); + response.setConfirmed(false); + return response; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public boolean isConfirmed() { + return confirmed; + } + + public void setConfirmed(boolean confirmed) { + this.confirmed = confirmed; + } + + public BigDecimal getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(BigDecimal totalAmount) { + this.totalAmount = totalAmount; + } + + public LocalDateTime getTimestamp() { + return timestamp; + } + + public void setTimestamp(LocalDateTime timestamp) { + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "OrderResponse{" + + "orderId='" + orderId + '\'' + + ", confirmed=" + confirmed + + ", totalAmount=" + totalAmount + + ", timestamp=" + timestamp + + '}'; + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/common/processing/PriceCalculator.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/processing/PriceCalculator.java new file mode 100644 index 00000000..c361dd43 --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/processing/PriceCalculator.java @@ -0,0 +1,81 @@ +/* + * 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.acme.rest.json.common.processing; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.enterprise.context.ApplicationScoped; +import org.acme.rest.json.common.model.Order; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Calculates order pricing based on customer ID. + * + * Customer tiers: + * - CUST001: GOLD (10% discount) + * - CUST004: PLATINUM (15% discount) + * - Others: STANDARD (no discount) + */ +@RegisterForReflection +@ApplicationScoped +public class PriceCalculator { + + private static final Logger log = LoggerFactory.getLogger(PriceCalculator.class); + private static final BigDecimal GOLD_DISCOUNT = new BigDecimal("0.10"); // 10% + private static final BigDecimal PLATINUM_DISCOUNT = new BigDecimal("0.15"); // 15% + + public void calculate(Order order) { + if (order == null) { + throw new IllegalArgumentException("Order cannot be null"); + } + + log.info("Calculating price for order: {}", order.getOrderId()); + + // Calculate subtotal from items + BigDecimal subtotal = order.calculateTotal(); + + // Apply customer discount based on customer ID + BigDecimal discount = getDiscountForCustomer(order.getCustomerId()); + BigDecimal discountAmount = subtotal.multiply(discount).setScale(2, RoundingMode.HALF_UP); + BigDecimal total = subtotal.subtract(discountAmount); + + if (discount.compareTo(BigDecimal.ZERO) > 0) { + log.info("Applied {}% discount: {}", discount.multiply(new BigDecimal("100")), discountAmount); + } + + order.setTotalAmount(total.setScale(2, RoundingMode.HALF_UP)); + + log.info("Final total for order {}: {}", order.getOrderId(), order.getTotalAmount()); + } + + private BigDecimal getDiscountForCustomer(String customerId) { + if (customerId == null) { + return BigDecimal.ZERO; + } + switch (customerId) { + case "CUST004": + return PLATINUM_DISCOUNT; + case "CUST001": + return GOLD_DISCOUNT; + default: + return BigDecimal.ZERO; + } + } +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/common/processing/ProcessedOrdersRegistry.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/processing/ProcessedOrdersRegistry.java new file mode 100644 index 00000000..d67385c0 --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/common/processing/ProcessedOrdersRegistry.java @@ -0,0 +1,53 @@ +/* + * 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.acme.rest.json.common.processing; + +import java.util.concurrent.CopyOnWriteArraySet; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.enterprise.context.ApplicationScoped; + +/** + * Thread-safe registry of processed order IDs. + * Used for testing to verify that orders are processed via Kafka. + */ +@ApplicationScoped +@RegisterForReflection +public class ProcessedOrdersRegistry { + + private final CopyOnWriteArraySet<String> processedOrderIds = new CopyOnWriteArraySet<>(); + + /** + * Registers an order as processed. + * + * @param orderId the order ID + */ + public void registerProcessed(String orderId) { + processedOrderIds.add(orderId); + } + + /** + * Checks if an order has been processed. + * + * @param orderId the order ID + * @return true if the order has been processed + */ + public boolean isProcessed(String orderId) { + return processedOrderIds.contains(orderId); + } + +} diff --git a/quarkus-rest-json/src/main/java/org/acme/rest/json/quarkus/OrderResource.java b/quarkus-rest-json/src/main/java/org/acme/rest/json/quarkus/OrderResource.java new file mode 100644 index 00000000..40015790 --- /dev/null +++ b/quarkus-rest-json/src/main/java/org/acme/rest/json/quarkus/OrderResource.java @@ -0,0 +1,87 @@ +/* + * 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.acme.rest.json.quarkus; + +import jakarta.inject.Inject; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import org.acme.rest.json.common.model.ErrorResponse; +import org.acme.rest.json.common.model.Order; +import org.acme.rest.json.common.model.OrderResponse; +import org.acme.rest.json.common.processing.ProcessedOrdersRegistry; +import org.apache.camel.ProducerTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("/api/orders") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class OrderResource { + + private static final Logger log = LoggerFactory.getLogger(OrderResource.class); + + @Inject + ProducerTemplate producerTemplate; + + @Inject + ProcessedOrdersRegistry registry; + + @POST + public Response createOrder(@Valid @NotNull Order order) { + // @NotNull and @Valid ensure order and its fields are validated before reaching here + log.info("Received order request for customer: {}", order.getCustomerId()); + + try { + // Delegate to Camel route for processing + OrderResponse response = producerTemplate.requestBody( + "direct:processOrder", + order, + OrderResponse.class); + + if (response == null) { + log.error("Order processing returned null response for order: {}", order.getOrderId()); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(ErrorResponse.of("Order processing failed", order.getOrderId())) + .build(); + } + + log.info("Order processing completed: {}", response.getOrderId()); + return Response.status(Response.Status.CREATED).entity(response).build(); + + } catch (Exception e) { + log.error("Failed to process order: {}", order.getOrderId(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(ErrorResponse.of("An error occurred while processing your order", order.getOrderId())) + .build(); + } + } + + /** + * Check if a specific order has been processed. + * + * @param orderId the order ID to check + * @return true if the order has been processed + */ + @GET + @Path("isProcessed/{orderId}") + public boolean isProcessed(@PathParam("orderId") String orderId) { + return registry.isProcessed(orderId); + } +} diff --git a/quarkus-rest-json/src/main/resources/application.properties b/quarkus-rest-json/src/main/resources/application.properties new file mode 100644 index 00000000..27fab82c --- /dev/null +++ b/quarkus-rest-json/src/main/resources/application.properties @@ -0,0 +1,101 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +# Use Strimzi as it's power architecture compatible +quarkus.kafka.devservices.provider = strimzi +quarkus.kafka.devservices.image-name = quay.io/strimzi-test-container/test-container:0.114.0-kafka-4.1.0 +quarkus.kafka.devservices.topic-partitions.orders-requests=3 + +# Kafka topic names +kafka.topic.orders.requests=orders-requests + +# Consumer group +kafka.consumer.group.id=order-processor-group + +# Kafka producer configuration - disable idempotent producer to avoid null key errors +camel.component.kafka.additional-properties[enable.idempotence]=false + +# Kafka brokers in native test and production +%test,prod.camel.component.kafka.brokers=${kafka.bootstrap.servers} + +# Kafka instance without Authentication +#camel.component.kafka.brokers=${brokers} + +# uncomment to set Kafka instance with SASL Plain +#camel.component.kafka.brokers=${brokers} +#camel.component.kafka.security-protocol=SASL_SSL +#camel.component.kafka.sasl-mechanism=PLAIN +#camel.component.kafka.sasl-jaas-config=org.apache.kafka.common.security.plain.PlainLoginModule required username="${id}" password="${secret}"; + +# uncomment to set Kafka instance with SASL Oauth Bearer +#camel.component.kafka.brokers = ${brokers} +#camel.component.kafka.security-protocol = SASL_SSL +#camel.component.kafka.sasl-mechanism = OAUTHBEARER +#camel.component.kafka.sasl-jaas-config = org.apache.kafka.common.security.oauthbearer.OAuthBearerLoginModule required \ +# oauth.client.id="${id}" \ +# oauth.client.secret="${secret}" \ +# oauth.token.endpoint.uri="${token}" ; +#camel.component.kafka.additional-properties[sasl.login.callback.handler.class] = io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler + + +################################### +# Kubernetes specific +################################### +# secrets +#quarkus.kubernetes-config.enabled=true +#getting secrets while deploying to kubernetes +#quarkus.kubernetes-config.namespace=test +#quarkus.kubernetes-config.secrets.enabled=true +#quarkus.kubernetes-config.secrets=camel-kafka + +# creating container with jib +#quarkus.container-image.build=true +#quarkus.kubernetes.deployment-target=kubernetes +#quarkus.container-image.group=<YOUR_IMAGE_GROUP> +#quarkus.container-image.registry=<YOUR_REGISTRY_URL> + +# Uncomment to trust self signed certificates if they are presented by the Kubernetes API server +#quarkus.kubernetes-client.trust-certs=true + +# Uncomment to set resource limits +#quarkus.kubernetes.resources.requests.memory=64Mi +#quarkus.kubernetes.resources.requests.cpu=250m +#quarkus.kubernetes.resources.limits.memory=512Mi +#quarkus.kubernetes.resources.limits.cpu=1000m + +################################### +# OpenShift specific +################################### +# secrets +#quarkus.kubernetes-config.enabled=true +#getting secrets while deploying to kubernetes +#quarkus.kubernetes-config.namespace=test +#quarkus.kubernetes-config.secrets.enabled=true +#quarkus.kubernetes-config.secrets=camel-kafka + +# creating container for openshift +#quarkus.container-image.build=true +#quarkus.kubernetes.deployment-target=openshift + +# OpenShift +#quarkus.openshift.image-pull-policy=IfNotPresent + +# Uncomment to set resource limits +#quarkus.openshift.resources.requests.memory=64Mi +#quarkus.openshift.resources.requests.cpu=250m +#quarkus.openshift.resources.limits.memory=512Mi +#quarkus.openshift.resources.limits.cpu=1000m diff --git a/quarkus-rest-json/src/test/java/org/acme/rest/json/OrderResoourceIT.java b/quarkus-rest-json/src/test/java/org/acme/rest/json/OrderResoourceIT.java new file mode 100644 index 00000000..aa6b100e --- /dev/null +++ b/quarkus-rest-json/src/test/java/org/acme/rest/json/OrderResoourceIT.java @@ -0,0 +1,25 @@ +/* + * 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.acme.rest.json; + +import io.quarkus.test.junit.QuarkusIntegrationTest; +import org.junit.jupiter.api.TestInstance; + +@QuarkusIntegrationTest +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class OrderResourceIT extends OrderResourceTest { +} diff --git a/quarkus-rest-json/src/test/java/org/acme/rest/json/OrderResourceTest.java b/quarkus-rest-json/src/test/java/org/acme/rest/json/OrderResourceTest.java new file mode 100644 index 00000000..b2f8ff05 --- /dev/null +++ b/quarkus-rest-json/src/test/java/org/acme/rest/json/OrderResourceTest.java @@ -0,0 +1,166 @@ +/* + * 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.acme.rest.json; + +import java.util.concurrent.TimeUnit; + +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.http.ContentType; +import io.restassured.response.Response; +import org.junit.jupiter.api.Test; + +import static io.restassured.RestAssured.get; +import static io.restassured.RestAssured.given; +import static org.awaitility.Awaitility.await; +import static org.hamcrest.CoreMatchers.*; + +@QuarkusTest +public class OrderResourceTest { + + private static final String ORDER_ENDPOINT = "/api/orders"; + + /** + * Checks if an order has been processed by querying the test endpoint. + * Works in both JVM and native modes. + * + * @param orderId the order ID to check + * @return true if the order has been processed + */ + protected boolean isOrderProcessed(String orderId) { + return given() + .log().ifValidationFails() // Only log on failure + .when() + .get(ORDER_ENDPOINT + "/isProcessed/" + orderId) + .then() + .statusCode(200) + .extract() + .as(Boolean.class); + } + + private static String createOrderJson(String customerId) { + return "{" + + "\"customerId\": \"" + customerId + "\"," + + "\"items\": [" + + "{" + + "\"productId\": \"PROD001\"," + + "\"productName\": \"Widget A\"," + + "\"quantity\": 1," + + "\"price\": 50.00" + + "}," + + "{" + + "\"productId\": \"PROD002\"," + + "\"productName\": \"Widget B\"," + + "\"quantity\": 2," + + "\"price\": 25.00" + + "}" + + "]" + + "}"; + } + + /** + * Test order creation with GOLD customer (10% discount). + * Subtotal: $100.00 + * Discount: 10% = $10.00 + * Expected Total: $90.00 + */ + @Test + public void testGoldCustomerDiscount() { + String orderJson = createOrderJson("CUST001"); + + Response response = given() + .contentType(ContentType.JSON) + .body(orderJson) + .when() + .post(ORDER_ENDPOINT) + .then() + .statusCode(201) + .body("confirmed", equalTo(true)) + .body("orderId", notNullValue()) + .body("totalAmount", equalTo(90.00f)) + .extract() + .response(); + + String orderId = response.jsonPath().getString("orderId"); + + // Verify order was processed via Kafka (works in both JVM and native modes) + await() + .atMost(30, TimeUnit.SECONDS) + .untilAsserted(() -> isOrderProcessed(orderId)); + } + + /** + * Test order creation with PLATINUM customer (15% discount). + * Subtotal: $100.00 + * Discount: 15% = $15.00 + * Expected Total: $85.00 + */ + @Test + public void testPlatinumCustomerDiscount() { + String orderJson = createOrderJson("CUST004"); + + Response response = given() + .contentType(ContentType.JSON) + .body(orderJson) + .when() + .post(ORDER_ENDPOINT) + .then() + .statusCode(201) + .body("confirmed", equalTo(true)) + .body("orderId", notNullValue()) + .body("totalAmount", equalTo(85.00f)) + .extract() + .response(); + + String orderId = response.jsonPath().getString("orderId"); + + // Verify order was processed via Kafka (works in both JVM and native modes) + await() + .atMost(10, TimeUnit.SECONDS) + .untilAsserted(() -> isOrderProcessed(orderId)); + } + + /** + * Test order creation with STANDARD customer (no discount). + * Subtotal: $100.00 + * Discount: 0% + * Expected Total: $100.00 + */ + @Test + public void testStandardCustomerNoDiscount() { + String orderJson = createOrderJson("CUST999"); + + Response response = given() + .contentType(ContentType.JSON) + .body(orderJson) + .when() + .post(ORDER_ENDPOINT) + .then() + .statusCode(201) + .body("confirmed", equalTo(true)) + .body("orderId", notNullValue()) + .body("totalAmount", equalTo(100.00f)) + .extract() + .response(); + + String orderId = response.jsonPath().getString("orderId"); + + // Verify order was processed via Kafka (works in both JVM and native modes) + await() + .atMost(10, TimeUnit.SECONDS) + .untilAsserted(() -> isOrderProcessed(orderId)); + } +} diff --git a/quarkus-rest-json/test-requests.sh b/quarkus-rest-json/test-requests.sh new file mode 100755 index 00000000..79d639de --- /dev/null +++ b/quarkus-rest-json/test-requests.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# +# 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. +# + + +# Test script for the Camel-Quarkus REST Integration Example + + +if ! jq --version &> /dev/null; then + echo "Error: jq is not installed. Please install it first." >&2 + exit 1 +fi + +# rest of your script... +BASE_URL="http://localhost:8080" + +echo "=========================================" +echo "Camel-Quarkus REST Integration Tests" +echo "=========================================" +echo "" + +# Colors for output +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Test 1: Create order with GOLD customer (10% discount) +echo -e "${BLUE}2. Creating order for GOLD customer (CUST001)...${NC}" +curl -s -X POST "${BASE_URL}/api/orders" \ + -H "Content-Type: application/json" \ + -d '{ + "customerId": "CUST001", + "items": [ + { + "productId": "PROD001", + "productName": "Widget A", + "quantity": 1, + "price": 50 + }, + { + "productId": "PROD002", + "productName": "Widget B", + "quantity": 2, + "price": 25 + } + ] + }' | jq . +echo -e "\n" + +# Test 2: PLATINUM customer (15% discount) +echo -e "${BLUE}3. Creating order for PLATINUM customer (CUST004)...${NC}" +curl -s -X POST "${BASE_URL}/api/orders" \ + -H "Content-Type: application/json" \ + -d '{ + "customerId": "CUST004", + "items": [ + { + "productId": "PROD001", + "productName": "Widget A", + "quantity": 1, + "price": 50 + }, + { + "productId": "PROD002", + "productName": "Widget B", + "quantity": 2, + "price": 25 + } + ] + }' | jq . +echo -e "\n" + +# Test 3: STANDARD customer (no discount) +echo -e "${BLUE}4. Creating order for STANDARD customer (CUST999)...${NC}" +curl -s -X POST "${BASE_URL}/api/orders" \ + -H "Content-Type: application/json" \ + -d '{ + "customerId": "CUST999", + "items": [ + { + "productId": "PROD001", + "productName": "Widget A", + "quantity": 1, + "price": 50 + }, + { + "productId": "PROD002", + "productName": "Widget B", + "quantity": 2, + "price": 25 + } + ] + }' | jq . +echo -e "\n" + +echo -e "${GREEN}=========================================${NC}" +echo -e "${GREEN}All tests completed!${NC}" +echo -e "${GREEN}=========================================${NC}"
