Reputation: 2911
I can run my Camel application using the camel-maven-plugin within maven (mvn camel:run). The camel-context.xml file is read and my routes start correctly.
My issues come about when I try to execute these camel routes on spring. When spring starts, I do not see any logs from Camel like I did when running the camel plugin directly. I also dont have any evidence that anything camel related has started. What is my configuration missing to successfully run the application? I am currently attempting to run this via an embedded tomcat instance (see mvn profile below). I would imagine that there is something unique that I need to do in order to get spring to find the camel context.
Thanks for any and all help!
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>---</groupId>
<artifactId>---</artifactId>
<version>1.0.6-SNAPSHOT</version>
</parent>
<artifactId>---</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>${packaging.type}</packaging>
<properties>
<jacoco.minimum.code.coverage>0.8</jacoco.minimum.code.coverage>
<packaging.type>war</packaging.type>
<failOnMissingWebXml>false</failOnMissingWebXml>
<org.apache.camel.version>2.16.0</org.apache.camel.version>
</properties>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-csv</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-aws</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>2.19.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>camel-maven-plugin</artifactId>
<version>2.19.2</version>
</plugin>
</plugins>
</build>
<profiles>
<!-- Default build profile for generating war -->
<profile>
<id>war</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<packaging.type>war</packaging.type>
<log.dir>${catalina.base}/logs</log.dir>
<!-- updates bootstrap.properties -->
<config.override.path>file:${catalina.base}/conf</config.override.path>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<descriptor>/src/main/resources/deployablecontent.xml</descriptor>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Build profile for stand-alone java application with embedded Tomcat
Container -->
<profile>
<id>embedded</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<packaging.type>jar</packaging.type>
<log.dir>logs</log.dir>
<!-- updates bootstrap.properties -->
<config.override.path>./conf</config.override.path>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>camel-maven-plugin</artifactId>
<version>2.19.2</version>
</plugin>
</plugins>
</build>
</profile>
</profiles>
My Routebuilder class:
public class PriorityCodeSourcesUpdaterRouteBuilder extends RouteBuilder {
private Endpoint incomingEndpoint;
private Endpoint outgoingEndpoint;
@Override
public void configure() throws Exception {
from(incomingEndpoint)
.process((exchange) -> {
System.out.println("new file received");
})
.to(outgoingEndpoint);
}
/**
* Set the incoming endpoint from the spring config file.
* @param incomingEndpoint incoming endpoint
*/
public void setIncomingEndpoint(final Endpoint incomingEndpoint) {
this.incomingEndpoint = incomingEndpoint;
}
/**
* Set the outgoing endpoint from the spring config file.
* @param outgoingEndpoint outgoing endpoint
*/
public void setOutgoingEndpoint(final Endpoint outgoingEndpoint) {
this.outgoingEndpoint = outgoingEndpoint;
}
}
My camel-context.xml that lives in resources/META-INF/spring/:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:camel="http://camel.apache.org/schema/spring" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<camel:camelContext id="camel">
<camel:routeBuilder ref="PriorityCodeSourcesUpdaterRouteBuilder"/>
<camel:endpoint id="incomingEndpoint" uri="">
<camel:property key="accessKey" value=""/>
<camel:property key="secretKey" value="RAW()"/>
<camel:property key="region" value=""/>
<camel:property key="deleteAfterRead" value="false"/>
</camel:endpoint>
<camel:endpoint id="outgoingEndpoint" uri="file://#{systemProperties['java.io.tmpdir']}">
<camel:property key="fileName" value="deadBeefName"/>
<camel:property key="readLock" value="markerFile "/>
<!-- We need a customer idempotentKey because all files sent to this endpoint have the same fileName. -->
<!-- This will prevent camel from thinking that it has already consumed the file. -->
<!--<camel:property key="idempotentKey" value="3"/>-->
</camel:endpoint>
</camel:camelContext>
<bean id="PriorityCodeSourcesUpdaterRouteBuilder" class=".....PriorityCodeSourcesUpdaterRouteBuilder">
<property name="incomingEndpoint" ref="incomingEndpoint" />
<property name="outgoingEndpoint" ref="outgoingEndpoint" />
</bean>
Upvotes: 1
Views: 14204
Reputation: 146
The answers are already there but i am adding my experience:
i.check if you have added below dependency in pom.xml if you are using spring boot
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>3.12.0</version>
</dependency>
ii. next check, if you have annotated your camel class which extends RouteBuilder with @Component
iii. check if you have annotated you main class with @ComponentScan or @SpingBootApplication to allow spring to pick up the configuration
Upvotes: 0
Reputation: 1
Please make sure that version of Spring Boot is compatible with Apache Camel. Camel will support Spring Boot 3.x from Apache Camel 4.x. You can read more in this thread.
Upvotes: 0
Reputation: 2371
As requested, below is a simplified version of Camel-Spring setup that we've been using in our Camel projects. Spring Boot is used (the goodies it offers are just too good to ignore, IMO) and we're also using web
starter. Since you're using WAR packaging anyway, this shouldn't be an issue to you.
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<artifactId>stackoverflow</artifactId>
<groupId>sandbox</groupId>
<version>1.0-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>2.19.2</version>
</dependency>
</dependencies>
</project>
src/main/java/stackoverflow/CamelRoute.java (the route definition, discovered automatically on startup, by the virtue of being placed in the package path of the @SpringBootApplication
class - the TestApp class below):
package stackoverflow;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class CamelRoute extends RouteBuilder {
@Value("${message}")
private String message;
// you can also have dependencies @Autowired here
@Override
public void configure() {
from("direct:test").process(exchange -> {
exchange.getIn().setBody(message);
});
}
}
src/main/resources/application.properties (to illustrate how can configuration values be passed on to your route definitions):
message=Test
src/main/resources/log4j.properties (mostly so that you would see your route started in the logs):
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-5p %c:%L - %m%n
src/main/java/stackoverflow/TestApp.java:
package stackoverflow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TestApp {
public static void main(String[] args) {
SpringApplication.run(TestApp.class, args);
}
}
The TestApp
class starts the application, and keeps running until stopped (it starts an embedded Tomcat server). The routes are discovered and started on app startup.
This setup prefers Java Configuration over XML, but if you still prefer the XML, you can import your configuration using @ImportResource
annotation on your TestApp. You will also be able to autowire the XML-configured classes into your route definitions.
Let me know if you have any questions about this setup.
Upvotes: 1
Reputation: 1151
TL;DR:
Try adding the camel-spring-boot-starter
dependency to your POM file, mark your route with @Component
annotation and add a @SpringBootApplication
class to start your Spring Context tied up with Camel.
Reading through your files I'm guessing that you are using Spring Boot, right?
If that so, it's nice to have the following dependencies in your POM:
<dependencyManagement>
<dependencies>
<!-- 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>
<!-- Camel BOM -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-dependencies</artifactId>
<version>${camel.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
This are the BOM (Bills of Materials) from both Spring Boot and Camel. This way all your required dependencies will be resolved nicely, plus avoiding the need to describe camel component's versions all the time.
It's a requirement to have the camel-context.xml
file? If it isn't you, could define everything on your RouteBuilder
class and put a @SpringBootApplication
annotation class on your classpath.
From the docs:
Spring Boot component provides auto-configuration for Apache Camel. Our opinionated auto-configuration of the Camel context auto-detects Camel routes available in the Spring context and registers the key Camel utilities (like producer template, consumer template and the type converter) as beans.
camel-spring-boot jar comes with the spring.factories file, so as soon as you add that dependency into your classpath, Spring Boot will automatically auto-configure Camel for you.
The problem I think you're facing is that there's no "glue" between your Spring Context and the Camel Context (camel-context.xml
file). Add the @Component
annotation to your RouteBuilder
and the following dependecy:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
Then these routes will be started automatically. To keep the main thread blocked so that Camel stays up, either include the spring-boot-starter-web dependency, or add camel.springboot.main-run-controller=true to your application.properties or application.yml file.
There's more information and examples in the docs.
Cheers!
Upvotes: 3