diff --git a/docs/modules/ROOT/attachments/examples.json b/docs/modules/ROOT/attachments/examples.json
index 89dbc38d..d2e7c049 100644
--- a/docs/modules/ROOT/attachments/examples.json
+++ b/docs/modules/ROOT/attachments/examples.json
@@ -4,11 +4,6 @@
"description": "Shows how to use Camel CXF SOAP component.",
"link": "https://github.com/apache/camel-quarkus-examples/tree/main/cxf-soap"
},
- {
- "title": "Connecting to a JDBC DataSource",
- "description": "Shows how to connect to a Database using Datastores.",
- "link": "https://github.com/apache/camel-quarkus-examples/tree/main/jdbc-datasource"
- },
{
"title": "Custom `main()`",
"description": "Shows how to start Camel from a custom `main()` method",
@@ -19,6 +14,11 @@
"description": "Shows how to deploy a Camel Quarkus route as an AWS Lambda function",
"link": "https://github.com/apache/camel-quarkus-examples/tree/main/aws-lambda"
},
+ {
+ "title": "Extract, Transform and Load between two databases",
+ "description": "Shows how to extract, transform and load between two databases",
+ "link": "https://github.com/apache/camel-quarkus-examples/tree/main/jdbc-datasource"
+ },
{
"title": "File consumer with Bindy \u0026 FTP",
"description": "Shows how to consume CSV files, marshal \u0026 unmarshal the data and send it onwards via FTP",
diff --git a/jdbc-datasource/README.adoc b/jdbc-datasource/README.adoc
index d44c5a01..b32eb02f 100644
--- a/jdbc-datasource/README.adoc
+++ b/jdbc-datasource/README.adoc
@@ -1,69 +1,118 @@
-= Connecting to a JDBC DataSource: A Camel Quarkus example
-:cq-example-description: An example that shows how to connect to a Database using Datastores.
+= Extract, Transform and Load between two databases: A Camel Quarkus example
+:cq-example-description: An example that shows how to extract, transform and load between two databases
{cq-description}
-In particular, it demonstrates the following:
+TIP: Check the https://camel.apache.org/camel-quarkus/latest/first-steps.html[Camel Quarkus User guide] for prerequisites
+and other general information.
-1. Defining a DataSource
-2. Querying the Database defined in the previous `DataSource`
-3. Usage of properties defined in `application.properties`
-4. No Java code required or used, the route defined in XML can still be compiled to native code.
+== Start the source and target databases
-This example will connect to an H2 database with the connection details defined in `application.properties`.
-If the example is run on Development mode and no database exists, Quarkus will create a matching database
-https://quarkus.io/guides/datasource#dev-services[as described here].
+All the commands in this example are expected to be run from the example directory, at the same level than the `pom.xml` file.
-TIP: Check the https://camel.apache.org/camel-quarkus/latest/first-steps.html[Camel Quarkus User guide] for prerequisites
-and other general information.
+In a first terminal, let's start the source database by executing the command below:
-== Start in the Development mode
+[source,shell]
+----
+docker run -p 5432:5432 \
+-e POSTGRES_USER=ETL_source_user \
+-e POSTGRES_PASSWORD=1234567@8_source \
+-e POSTGRES_DB=source_db \
+-v ${PWD}/src/test/resources/init-source-db.sql:/docker-entrypoint-initdb.d/init-source-db.sql \
+docker.io/postgres:15.0
+----
+
+In a second terminal, let's start the target database:
[source,shell]
----
-$ mvn clean compile quarkus:dev
+docker run -p 5433:5432 \
+-e POSTGRES_USER=ETL_target_user \
+-e POSTGRES_PASSWORD=1234567@8_target \
+-e POSTGRES_DB=target_db \
+-v ${PWD}/src/test/resources/init-target-db.sql:/docker-entrypoint-initdb.d/init-target-db.sql \
+docker.io/postgres:15.0
----
-The above command compiles the project, starts the application and lets the Quarkus tooling watch for changes in your
-workspace. Any modifications in your project will automatically take effect in the running application.
+== Running the application in dev mode
+
+You can run your application in dev mode that enables live coding using:
+
+[source,shell]
+----
+mvn compile quarkus:dev
+----
+
+[NOTE]
+====
+Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/.
+====
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.
-=== Package and run the application
+Extract, Transform and Load related logs should be output as below:
+
+[source,shell]
+----
+2023-11-14 15:12:55,878 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) Extracting data from source database
+2023-11-14 15:12:55,881 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) -> Transforming review for hotel 'Grand Hotel'
+2023-11-14 15:12:55,886 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) -> Loading transformed data in target database
+2023-11-14 15:12:55,893 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) -> Transforming review for hotel 'Middle Hotel'
+2023-11-14 15:12:55,897 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) -> Loading transformed data in target database
+2023-11-14 15:12:55,904 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) -> Transforming review for hotel 'Small Hotel'
+2023-11-14 15:12:55,909 INFO [route17] (Camel (camel-9) thread #9 - timer://insertCamel) -> Loading transformed data in target database
+----
+
+=== Packaging and running the application
Once you are done with developing you may want to package and run the application.
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]
-==== JVM mode
+The application can be packaged using:
[source,shell]
----
-$ mvn clean package
-$ java -jar target/quarkus-app/quarkus-run.jar
-...
+mvn package
+----
+
+It produces the `quarkus-run.jar` file in the `target/quarkus-app/` directory.
+Be aware that it’s not an _über-jar_ as the dependencies are copied into the `target/quarkus-app/lib/` directory.
+
+The application is now runnable executing the command below:
-[io.quarkus] (main) camel-quarkus-examples-... started in 0.570s.
+[source,shell]
+----
+java -jar target/quarkus-app/quarkus-run.jar
----
-==== Native mode
+The application should output the same logs than in previous section.
+
+==== Creating a native executable
+
+Finally, the application can be compiled to native with the following command:
-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].
+[source,shell]
+----
+mvn package -Dnative
+----
+
+Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
+
+[source,shell]
+----
+mvn package -Dnative -Dquarkus.native.container-build=true
+----
-To prepare a native executable using GraalVM, run the following command:
+Either way, the resulting native executable could be start as below:
[source,shell]
----
-$ mvn clean package -Pnative
-$ ./target/*-runner
-...
-[io.quarkus] (main) camel-quarkus-examples-... started in 0.011s.
-...
+./target/*-runner
----
-== Feedback
+The application should output the same logs than in previous section.
-Please report bugs and propose improvements via https://github.com/apache/camel-quarkus/issues[GitHub issues of Camel Quarkus] project.
+If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.
\ No newline at end of file
diff --git a/jdbc-datasource/pom.xml b/jdbc-datasource/pom.xml
index 3eaa0407..24912433 100644
--- a/jdbc-datasource/pom.xml
+++ b/jdbc-datasource/pom.xml
@@ -66,50 +66,59 @@
-
- org.apache.camel.quarkus
- camel-quarkus-microprofile-health
-
-
- org.apache.camel.quarkus
- camel-quarkus-xml-io-dsl
-
-
- org.apache.camel.quarkus
- camel-quarkus-log
-
-
- org.apache.camel.quarkus
- camel-quarkus-timer
-
-
- org.apache.camel.quarkus
- camel-quarkus-jdbc
-
-
- io.quarkus
- quarkus-jdbc-h2
-
-
- io.quarkus
- quarkus-agroal
-
-
- io.quarkus
- quarkus-junit5
- test
-
-
- io.quarkus
- quarkus-test-h2
- test
-
-
- org.awaitility
- awaitility
- test
-
-
+
+ org.apache.camel.quarkus
+ camel-quarkus-bean
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-core
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-jdbc
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-timer
+
+
+ org.apache.camel.quarkus
+ camel-quarkus-platform-http
+
+
+ io.quarkus
+ quarkus-agroal
+
+
+ io.quarkus
+ quarkus-jdbc-postgresql
+
+
+ io.quarkus
+ quarkus-arc
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ org.testcontainers
+ testcontainers
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+ org.awaitility
+ awaitility
+ test
+
+
@@ -184,6 +193,7 @@
**/NOTICE
**/README
**/pom.xml.versionsBackup
+ **/quarkus.log*
SLASHSTAR_STYLE
@@ -273,5 +283,16 @@
native
+
+ skip-testcontainers-tests
+
+
+ skip-testcontainers-tests
+
+
+
+ true
+
+
diff --git a/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcRoutes.java b/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcRoutes.java
index 3298db0e..3afa3317 100644
--- a/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcRoutes.java
+++ b/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcRoutes.java
@@ -16,19 +16,37 @@
*/
package org.acme.jdbc;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.camel.builder.RouteBuilder;
public class JdbcRoutes extends RouteBuilder {
@Override
public void configure() throws Exception {
- from("timer://insertCamel?period=1000")
- .log("Inserting Camel ${messageTimestamp}")
- .setBody().simple("INSERT INTO Camel (timestamp) VALUES (${messageTimestamp})")
- .to("jdbc:camel-ds")
- .log("Inserted Camel ${messageTimestamp}")
- .setBody().simple("SELECT * FROM Camel")
- .to("jdbc:camel-ds")
- .log("We have ${header[CamelJdbcRowCount]} camels in the database.")
- .log("Camels found: ${body}");
+ // Define a mapping for the review values
+ HashMap reviewMapping = new HashMap<>();
+ reviewMapping.put("best", 1);
+ reviewMapping.put("good", 0);
+ reviewMapping.put("worst", -1);
+
+ from("timer://insertCamel?period=1000&repeatCount={{etl.timer.repeatcount}}")
+ .setBody().simple("DELETE FROM Target")
+ .to("jdbc:target_db")
+ .setBody().simple("SELECT * FROM Source")
+ .to("jdbc:source_db")
+ .log("Extracting data from source database")
+ .split(body())
+ .process(exchange -> {
+ Map sourceData = exchange.getIn().getBody(Map.class);
+ String review = (String) sourceData.get("review");
+ int mappedReview = reviewMapping.getOrDefault(review, 0);
+ sourceData.put("review", mappedReview);
+ })
+ .log("-> Transforming review for hotel '${body[hotel_name]}'")
+ .setBody()
+ .simple("INSERT INTO Target (id, hotel_name, price, review) VALUES(${body[id]}, '${body[hotel_name]}', ${body[price]}, ${body[review]})")
+ .to("jdbc:target_db")
+ .log("-> Loading transformed data in target database");
}
}
diff --git a/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcResource.java b/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcService.java
similarity index 59%
rename from jdbc-datasource/src/main/java/org/acme/jdbc/JdbcResource.java
rename to jdbc-datasource/src/main/java/org/acme/jdbc/JdbcService.java
index 5e6f9fa6..9aa2caee 100644
--- a/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcResource.java
+++ b/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcService.java
@@ -16,31 +16,35 @@
*/
package org.acme.jdbc;
-import java.sql.Connection;
-import java.sql.Statement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
import io.agroal.api.AgroalDataSource;
import io.quarkus.agroal.DataSource;
-import io.quarkus.runtime.StartupEvent;
+import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
-import org.apache.camel.CamelContext;
+import jakarta.inject.Named;
+@Named("reviewService")
@ApplicationScoped
-public class JdbcResource {
+@RegisterForReflection
+public class JdbcService {
@Inject
- @DataSource("camel-ds")
- AgroalDataSource dataSource;
-
- void startup(@Observes StartupEvent event, CamelContext context) throws Exception {
- try (Connection con = dataSource.getConnection()) {
- try (Statement statement = con.createStatement()) {
- con.setAutoCommit(true);
- statement.execute("DROP TABLE IF EXISTS camel");
- statement.execute("CREATE TABLE camel (id SERIAL PRIMARY KEY, timestamp VARCHAR(255))");
- }
+ @DataSource("target_db")
+ AgroalDataSource targetDb;
+
+ String getHotelReviews() throws SQLException {
+
+ StringBuilder sb = new StringBuilder();
+
+ ResultSet rs = targetDb.getConnection().createStatement().executeQuery("SELECT (hotel_name, review) FROM Target");
+
+ while (rs.next()) {
+ sb.append(rs.getString(1));
}
+
+ return sb.toString();
}
}
diff --git a/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcTestHarness.java b/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcTestHarness.java
new file mode 100644
index 00000000..17b2256b
--- /dev/null
+++ b/jdbc-datasource/src/main/java/org/acme/jdbc/JdbcTestHarness.java
@@ -0,0 +1,27 @@
+/*
+ * 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.jdbc;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class JdbcTestHarness extends RouteBuilder {
+ @Override
+ public void configure() throws Exception {
+ from("platform-http:/getHotelReviews")
+ .bean("reviewService", "getHotelReviews");
+ }
+}
diff --git a/jdbc-datasource/src/main/resources/application.properties b/jdbc-datasource/src/main/resources/application.properties
index b178e026..706c31d5 100644
--- a/jdbc-datasource/src/main/resources/application.properties
+++ b/jdbc-datasource/src/main/resources/application.properties
@@ -20,20 +20,18 @@
quarkus.banner.enabled = false
quarkus.log.file.enable = true
-#Default DataSource
-quarkus.datasource.camel-ds.db-kind=h2
+# Set how many time the route should be applied
+etl.timer.repeatcount = 0
+%test.etl.timer.repeatCount = 1
-#If you want to have more than one DataSource, you can use an identifier as this:
-#quarkus.datasource.$identifier.db-kind=h2
-#Then use it on the route by name
-#.to("jdbc:$identifier")
+# Source Database Configuration
+quarkus.datasource.source_db.db-kind = postgresql
+quarkus.datasource.source_db.jdbc.url = jdbc:postgresql://localhost:5432/source_db
+quarkus.datasource.source_db.username = ETL_source_user
+quarkus.datasource.source_db.password = 1234567@8_source
-#Configure the following section to use a maven profile (called prod)
-#configured database (using postgresql on this case)
-#Remember to edit the pom.xml to add the database driver needed
-#quarkus-jdbc-postgresql on this case
-#%prod.quarkus.datasource.db-kind=postgresql
-#%prod.quarkus.datasource.username=${POSTGRESQL_USER}
-#%prod.quarkus.datasource.password=${POSTGRESQL_PASSWORD}
-#%prod.quarkus.datasource.jdbc.url=${POSTGRESQL_JDBC_URL}
-#%prod.quarkus.datasource.jdbc.max-size=16
\ No newline at end of file
+# Target Database Configuration
+quarkus.datasource.target_db.db-kind = postgresql
+quarkus.datasource.target_db.jdbc.url = jdbc:postgresql://localhost:5433/target_db
+quarkus.datasource.target_db.username = ETL_target_user
+quarkus.datasource.target_db.password = 1234567@8_target
diff --git a/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcDataSourceIT.java b/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcIT.java
similarity index 94%
rename from jdbc-datasource/src/test/java/org/acme/jdbc/JdbcDataSourceIT.java
rename to jdbc-datasource/src/test/java/org/acme/jdbc/JdbcIT.java
index 41c899ef..c6595e16 100644
--- a/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcDataSourceIT.java
+++ b/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcIT.java
@@ -19,6 +19,5 @@
import io.quarkus.test.junit.QuarkusIntegrationTest;
@QuarkusIntegrationTest
-class JdbcDataSourceIT extends JdbcDataSourceTest {
-
+public class JdbcIT extends JdbcTest {
}
diff --git a/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcDataSourceTest.java b/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcTest.java
similarity index 58%
rename from jdbc-datasource/src/test/java/org/acme/jdbc/JdbcDataSourceTest.java
rename to jdbc-datasource/src/test/java/org/acme/jdbc/JdbcTest.java
index e38dbd50..18b3de7e 100644
--- a/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcDataSourceTest.java
+++ b/jdbc-datasource/src/test/java/org/acme/jdbc/JdbcTest.java
@@ -16,32 +16,29 @@
*/
package org.acme.jdbc;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import io.quarkus.test.common.QuarkusTestResource;
-import io.quarkus.test.h2.H2DatabaseTestResource;
import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static org.awaitility.Awaitility.await;
@QuarkusTest
-@QuarkusTestResource(H2DatabaseTestResource.class)
-public class JdbcDataSourceTest {
+@QuarkusTestResource(PostgresSourceDatabaseTestResource.class)
+@QuarkusTestResource(PostgresTargetDatabaseTestResource.class)
+public class JdbcTest {
+
@Test
- public void testCamelsInDatabase() throws Exception {
- // Verify that camels are being inserted in the database:
- await()
- .atMost(10L, TimeUnit.SECONDS)
- .pollDelay(1, TimeUnit.SECONDS)
- .until(() -> {
- String log = new String(Files.readAllBytes(
- Paths.get("target/quarkus.log")),
- StandardCharsets.UTF_8);
- return log.contains("We have 2 camels in the database.");
- });
+ public void etlBridgeShouldTransferValuesBetweenDatebases() {
+ await().atMost(30L, TimeUnit.SECONDS).pollDelay(500, TimeUnit.MILLISECONDS).until(() -> {
+ String hotelReviews = RestAssured
+ .get("/getHotelReviews")
+ .then()
+ .extract().asString();
+
+ return "(\"Grand Hotel\",1)(\"Middle Hotel\",0)(\"Small Hotel\",-1)".equals(hotelReviews);
+ });
}
}
diff --git a/jdbc-datasource/src/test/java/org/acme/jdbc/PostgresSourceDatabaseTestResource.java b/jdbc-datasource/src/test/java/org/acme/jdbc/PostgresSourceDatabaseTestResource.java
new file mode 100644
index 00000000..b0f9a142
--- /dev/null
+++ b/jdbc-datasource/src/test/java/org/acme/jdbc/PostgresSourceDatabaseTestResource.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jdbc;
+
+import java.util.Map;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.BindMode;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.TestcontainersConfiguration;
+
+import static org.apache.camel.util.CollectionHelper.mapOf;
+
+public class PostgresSourceDatabaseTestResource implements QuarkusTestResourceLifecycleManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PostgresSourceDatabaseTestResource.class);
+
+ private static final int POSTGRES_PORT = 5432;
+ private static final String POSTGRES_IMAGE = "docker.io/postgres:15.0";
+
+ private static final String POSTGRES_SOURCE_DB_NAME = "source_db";
+ private static final String POSTGRES_SOURCE_PASSWORD = "1234567@8_source";
+ private static final String POSTGRES_SOURCE_USER = "ETL_source_user";
+
+ private GenericContainer> sourceDbContainer;
+
+ @Override
+ public Map start() {
+ LOG.info(TestcontainersConfiguration.getInstance().toString());
+
+ sourceDbContainer = new GenericContainer<>(POSTGRES_IMAGE)
+ .withExposedPorts(POSTGRES_PORT)
+ .withEnv("POSTGRES_USER", POSTGRES_SOURCE_USER)
+ .withEnv("POSTGRES_PASSWORD", POSTGRES_SOURCE_PASSWORD)
+ .withEnv("POSTGRES_DB", POSTGRES_SOURCE_DB_NAME)
+ .withClasspathResourceMapping("init-source-db.sql", "/docker-entrypoint-initdb.d/init-source-db.sql",
+ BindMode.READ_ONLY)
+ .withLogConsumer(new Slf4jLogConsumer(LOG)).waitingFor(Wait.forListeningPort());
+ sourceDbContainer.start();
+
+ // Print Postgres server connectivity information
+ String sourceJbdcUrl = String.format("jdbc:postgresql://%s:%s/%s", sourceDbContainer.getHost(),
+ sourceDbContainer.getMappedPort(POSTGRES_PORT), POSTGRES_SOURCE_DB_NAME);
+ LOG.info("The test source_db could be accessed through the following JDBC url: " + sourceJbdcUrl);
+
+ return mapOf("quarkus.datasource.source_db.jdbc.url", sourceJbdcUrl);
+ }
+
+ @Override
+ public void stop() {
+ try {
+ if (sourceDbContainer != null) {
+ sourceDbContainer.stop();
+ }
+ } catch (Exception ex) {
+ LOG.error("An issue occured while stopping the sourceDbContainer", ex);
+ }
+ }
+
+}
diff --git a/jdbc-datasource/src/test/java/org/acme/jdbc/PostgresTargetDatabaseTestResource.java b/jdbc-datasource/src/test/java/org/acme/jdbc/PostgresTargetDatabaseTestResource.java
new file mode 100644
index 00000000..3f67ff19
--- /dev/null
+++ b/jdbc-datasource/src/test/java/org/acme/jdbc/PostgresTargetDatabaseTestResource.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jdbc;
+
+import java.util.Map;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.BindMode;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.TestcontainersConfiguration;
+
+import static org.apache.camel.util.CollectionHelper.mapOf;
+
+public class PostgresTargetDatabaseTestResource implements QuarkusTestResourceLifecycleManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PostgresTargetDatabaseTestResource.class);
+
+ private static final int POSTGRES_PORT = 5432;
+ private static final String POSTGRES_IMAGE = "docker.io/postgres:15.0";
+
+ private static final String POSTGRES_TARGET_DB_NAME = "target_db";
+ private static final String POSTGRES_TARGET_PASSWORD = "1234567@8_target";
+ private static final String POSTGRES_TARGET_USER = "ETL_target_user";
+
+ private GenericContainer> targetDbContainer;
+
+ @Override
+ public Map start() {
+ LOG.info(TestcontainersConfiguration.getInstance().toString());
+
+ targetDbContainer = new GenericContainer<>(POSTGRES_IMAGE)
+ .withExposedPorts(POSTGRES_PORT)
+ .withEnv("POSTGRES_USER", POSTGRES_TARGET_USER)
+ .withEnv("POSTGRES_PASSWORD", POSTGRES_TARGET_PASSWORD)
+ .withEnv("POSTGRES_DB", POSTGRES_TARGET_DB_NAME)
+ .withClasspathResourceMapping("init-target-db.sql", "/docker-entrypoint-initdb.d/init-target-db.sql",
+ BindMode.READ_ONLY)
+ .withLogConsumer(new Slf4jLogConsumer(LOG)).waitingFor(Wait.forListeningPort());
+ targetDbContainer.start();
+
+ // Print Postgres server connectivity information
+ String targetJbdcUrl = String.format("jdbc:postgresql://%s:%s/%s", targetDbContainer.getHost(),
+ targetDbContainer.getMappedPort(POSTGRES_PORT), POSTGRES_TARGET_DB_NAME);
+ LOG.info("The test target_db could be accessed through the following JDBC url: " + targetJbdcUrl);
+
+ return mapOf("quarkus.datasource.target_db.jdbc.url", targetJbdcUrl);
+ }
+
+ @Override
+ public void stop() {
+ try {
+ if (targetDbContainer != null) {
+ targetDbContainer.stop();
+ }
+ } catch (Exception ex) {
+ LOG.error("An issue occured while stopping the targetDbContainer", ex);
+ }
+ }
+
+}
diff --git a/jdbc-datasource/src/test/resources/init-source-db.sql b/jdbc-datasource/src/test/resources/init-source-db.sql
new file mode 100644
index 00000000..0b0c7cbb
--- /dev/null
+++ b/jdbc-datasource/src/test/resources/init-source-db.sql
@@ -0,0 +1,23 @@
+--
+-- 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.
+--
+
+CREATE TABLE IF NOT EXISTS Source (id SERIAL PRIMARY KEY, hotel_name VARCHAR(255), price DECIMAL, review VARCHAR(255));
+
+INSERT INTO Source (id, hotel_name, price, review) VALUES
+(1, 'Grand Hotel', 100, 'best'),
+(2, 'Middle Hotel', 20, 'good'),
+(3, 'Small Hotel', 17, 'worst');
\ No newline at end of file
diff --git a/jdbc-datasource/src/test/resources/init-target-db.sql b/jdbc-datasource/src/test/resources/init-target-db.sql
new file mode 100644
index 00000000..15eef387
--- /dev/null
+++ b/jdbc-datasource/src/test/resources/init-target-db.sql
@@ -0,0 +1,18 @@
+--
+-- 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.
+--
+
+CREATE TABLE IF NOT EXISTS Target (id SERIAL PRIMARY KEY, hotel_name VARCHAR(255), price DECIMAL, review DECIMAL);
\ No newline at end of file