This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-spring-boot-examples.git
The following commit(s) were added to refs/heads/main by this push: new 8b2b022 add tomcat-jdbc example (#136) 8b2b022 is described below commit 8b2b022d75d32c0472b441307d4ece4f5e29489a Author: Rinaldo Pitzer JĂșnior <16694899+rinaldo...@users.noreply.github.com> AuthorDate: Thu Aug 8 13:54:20 2024 -0300 add tomcat-jdbc example (#136) --- tomcat-jdbc/pom.xml | 150 +++++++++++++++++++++ tomcat-jdbc/readme.adoc | 58 ++++++++ tomcat-jdbc/src/main/java/sample/camel/MyBean.java | 40 ++++++ .../main/java/sample/camel/MyCamelApplication.java | 50 +++++++ .../src/main/java/sample/camel/MyCamelRouter.java | 59 ++++++++ .../src/main/resources/application.properties | 51 +++++++ tomcat-jdbc/src/main/resources/schema.sql | 5 + .../sample/camel/MyCamelApplicationJUnit5Test.java | 71 ++++++++++ 8 files changed, 484 insertions(+) diff --git a/tomcat-jdbc/pom.xml b/tomcat-jdbc/pom.xml new file mode 100644 index 0000000..03ad5be --- /dev/null +++ b/tomcat-jdbc/pom.xml @@ -0,0 +1,150 @@ +<?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/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.camel.springboot.example</groupId> + <artifactId>examples</artifactId> + <version>4.7.0-SNAPSHOT</version> + </parent> + + <artifactId>camel-example-spring-boot</artifactId> + <name>Camel SB Examples :: Tomcat JDBC</name> + <description>An example showing how to deploy a Camel Spring Boot application in Tomcat using its JDBC Data Source</description> + <packaging>war</packaging> + + <properties> + <category>Beginner</category> + + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <!-- Camel BOM --> + <dependency> + <groupId>org.apache.camel.springboot</groupId> + <artifactId>camel-spring-boot-bom</artifactId> + <version>${camel-version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + <!-- Spring Boot BOM --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-dependencies</artifactId> + <version>${spring-boot-version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + + <!-- Spring Boot --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-jdbc</artifactId> + <exclusions> + <exclusion> + <!-- Spring Boot uses HikariCP DataSource by default, so we remove it --> + <groupId>com.zaxxer</groupId> + <artifactId>HikariCP</artifactId> + </exclusion> + </exclusions> + </dependency> + + <!-- Tomcat --> + <!-- Those dependencies will be provided by the tomcat server and therefore must be flagged as 'provided' --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jdbc</artifactId> + <scope>provided</scope> + </dependency> + + <!-- db driver --> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + + <!-- Camel --> + <dependency> + <groupId>org.apache.camel.springboot</groupId> + <artifactId>camel-spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.springboot</groupId> + <artifactId>camel-spring-jdbc-starter</artifactId> + </dependency> + + <!-- test --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-spring-junit5</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <finalName>${artifactId}</finalName> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>${spring-boot-version}</version> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/tomcat-jdbc/readme.adoc b/tomcat-jdbc/readme.adoc new file mode 100644 index 0000000..1d6b9b6 --- /dev/null +++ b/tomcat-jdbc/readme.adoc @@ -0,0 +1,58 @@ +== Camel Spring Boot example with Tomcat and database connection + +This example shows how to work with a simple Apache Camel Spring Boot application deploying to Tomcat and using its JDBC data source. + +The example generates 2 routes: + +. The first route is triggered by a timer and writes messages to the database. +. The second route is triggered by a timer and read the COUNT of messages from the database. + +=== Classes + +* `MyCamelRouter`: where the camel routes are defined +* `MyBean`: used to generate a simple message with a counter +* `MyCamelApplication`: the Spring Boot servlet initializer + +=== How to deploy + +. Run the database container +[source,console] +podman run --rm --name db -e POSTGRES_PASSWORD=password -p 5432:5432 docker.io/library/postgres:latest + +. Run the tests and package the `war` file +[source,console] +mvn clean package + +. Copy the `war` file to your tomcat `webapps` directory +[source,console] +cp target/camel-example-spring-boot.war <your_tomcat_dir>/webapps/ + +. Run tomcat +[source,console] +sh <your_tomcat_dir>/bin/catalina.sh run + +. Look for the log messages in the console +[source,log] +[- timer://hello] ... Body: insert into messages(message) values('Hello World I am invoked 1 times')] +[- timer://query] ... Body: There are 0 messages in the database.] +[- timer://query] ... Body: There are 1 messages in the database.] +[- timer://hello] ... Body: insert into messages(message) values('Hello World I am invoked 2 times')] +[- timer://query] ... Body: There are 2 messages in the database.] +[- timer://hello] ... Body: insert into messages(message) values('Hello World I am invoked 3 times')] +[- timer://query] ... Body: There are 3 messages in the database.] +[- timer://hello] ... Body: insert into messages(message) values('Hello World I am invoked 4 times')] +[- timer://hello] ... Body: insert into messages(message) values('Hello World I am invoked 5 times')] +[- timer://query] ... Body: There are 4 messages in the database.] + +=== Help and contributions + +If you hit any problem using Camel or have some feedback, then please +https://camel.apache.org/support.html[let us know]. + +We also love contributors, so +https://camel.apache.org/contributing.html[get involved] :-) + +The Camel riders! + + + diff --git a/tomcat-jdbc/src/main/java/sample/camel/MyBean.java b/tomcat-jdbc/src/main/java/sample/camel/MyBean.java new file mode 100644 index 0000000..45b9aa8 --- /dev/null +++ b/tomcat-jdbc/src/main/java/sample/camel/MyBean.java @@ -0,0 +1,40 @@ +/* + * 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 sample.camel; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +/** + * A bean that returns a message when you call the {@link #saySomething()} method. + * <p/> + * Uses <tt>@Component("myBean")</tt> to register this bean with the name <tt>myBean</tt> + * that we use in the Camel route to lookup this bean. + */ +@Component("myBean") +public class MyBean { + + private int counter; + + @Value("${greeting}") + private String say; + + public String saySomething(String body) { + return String.format("%s I am invoked %d times", say, ++counter); + } + +} diff --git a/tomcat-jdbc/src/main/java/sample/camel/MyCamelApplication.java b/tomcat-jdbc/src/main/java/sample/camel/MyCamelApplication.java new file mode 100644 index 0000000..d680ead --- /dev/null +++ b/tomcat-jdbc/src/main/java/sample/camel/MyCamelApplication.java @@ -0,0 +1,50 @@ +/* + * 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 sample.camel; + +import org.springframework.boot.Banner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Configuration; + +//CHECKSTYLE:OFF +/** + * A sample Spring Boot application that starts the Camel routes. + * + * Having both the {@link #configure} and {@link #main} methods call the same builder ensures the configuration + * will be applied either by starting the application as a .war or by running as an executable. + */ +@SpringBootApplication +public class MyCamelApplication extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { + return customizerBuilder(builder); + } + + public static void main(String[] args) { + customizerBuilder(new SpringApplicationBuilder()).run(args); + } + + private static SpringApplicationBuilder customizerBuilder(SpringApplicationBuilder builder) { + return builder.sources(MyCamelApplication.class); + } + +} +//CHECKSTYLE:ON diff --git a/tomcat-jdbc/src/main/java/sample/camel/MyCamelRouter.java b/tomcat-jdbc/src/main/java/sample/camel/MyCamelRouter.java new file mode 100644 index 0000000..71fedd3 --- /dev/null +++ b/tomcat-jdbc/src/main/java/sample/camel/MyCamelRouter.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.camel; + +import org.apache.camel.builder.RouteBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * A simple Camel route that triggers from a timer and calls a bean and prints to system out. + * <p/> + * Use <tt>@Component</tt> to make Camel auto-detect this route when starting. + */ +@Component +public class MyCamelRouter extends RouteBuilder { + + // we can use spring dependency injection + @Autowired + MyBean myBean; + + @Override + public void configure() throws Exception { + // route to keep inserting messages in the database + // start from a timer + from("timer:hello?period={{myPeriod}}") + .routeId("hello") + // store the message from the bean in a header + .setHeader("message").method(myBean, "saySomething") + // prepare the insert SQL + .setBody(simple("insert into messages(message) values('${header.message}')")) + // insert the message into the database + .to("spring-jdbc:default") + // print the body + .to("log:info"); + + // route to print inserted messages + from("timer:query?period={{myPeriod}}") + .routeId("query") + .setBody(constant("select count(*) as \"C\" from messages")) + .to("spring-jdbc:default") + .setBody(simple("There are ${body[0][C]} messages in the database.")) + .to("log:info"); + } + +} diff --git a/tomcat-jdbc/src/main/resources/application.properties b/tomcat-jdbc/src/main/resources/application.properties new file mode 100644 index 0000000..cec869a --- /dev/null +++ b/tomcat-jdbc/src/main/resources/application.properties @@ -0,0 +1,51 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +# the name of Camel +camel.springboot.name = MyCamel + +spring.datasource.type=org.apache.tomcat.jdbc.pool.DataSource +// other spring datasource properties +#database configuration +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.username=postgres +spring.datasource.password=password +#init schema.sql -- this should be changed for production use! +spring.sql.init.mode=always + +# what to say +greeting = Hello World + +# how often to trigger the timer (millis) +myPeriod = 2000 + +# expose actuator endpoint via HTTP +#management.endpoints.web.exposure.include=info,health,camel + +# show verbose health details (/actuator/health) so you can see Camel information also +management.endpoint.health.show-details=always + +# to turn off Camel info in (/actuator/info) +#management.info.camel.enabled=false + +# to configure logging levels +#logging.level.org.springframework = INFO +#logging.level.org.apache.camel.spring.boot = INFO +#logging.level.org.apache.camel.impl = DEBUG +#logging.level.sample.camel = DEBUG + diff --git a/tomcat-jdbc/src/main/resources/schema.sql b/tomcat-jdbc/src/main/resources/schema.sql new file mode 100644 index 0000000..16e8eb5 --- /dev/null +++ b/tomcat-jdbc/src/main/resources/schema.sql @@ -0,0 +1,5 @@ +DROP TABLE IF EXISTS messages; +CREATE TABLE messages ( + message VARCHAR(255), + ts TIMESTAMP NOT NULL DEFAULT now() +); \ No newline at end of file diff --git a/tomcat-jdbc/src/test/java/sample/camel/MyCamelApplicationJUnit5Test.java b/tomcat-jdbc/src/test/java/sample/camel/MyCamelApplicationJUnit5Test.java new file mode 100644 index 0000000..4952c34 --- /dev/null +++ b/tomcat-jdbc/src/test/java/sample/camel/MyCamelApplicationJUnit5Test.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package sample.camel; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.NotifyBuilder; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.apache.camel.test.spring.junit5.EnableRouteCoverage; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.jdbc.EmbeddedDatabaseConnection; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Example test class with Camel coverage. When running tests a mock web server will be running, simulating a web environment. + */ +@CamelSpringBootTest +@SpringBootTest(classes = MyCamelApplication.class) +@AutoConfigureTestDatabase(connection = EmbeddedDatabaseConnection.H2) +@EnableRouteCoverage +public class MyCamelApplicationJUnit5Test { + + @Autowired + private CamelContext camelContext; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Test + public void shouldProduceMessages() throws Exception { + // we expect that one or more messages is automatically done by the Camel + // route as it uses a timer to trigger + NotifyBuilder notify = new NotifyBuilder(camelContext).whenDone(1).create(); + assertTrue(notify.matches(5, TimeUnit.SECONDS)); + + // check if the correct message is in the database + List<Map<String, Object>> messages = jdbcTemplate.queryForList("select * from messages"); + assertTrue(!messages.isEmpty()); + assertTrue(messages.get(0).containsValue("Hello World I am invoked 1 times")); + } + +}