Chad Van De Hey
Chad Van De Hey

Reputation: 2911

Camel not starting in spring

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

Answers (4)

kumarras
kumarras

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

Damian Baliński
Damian Baliński

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

Alex Savitsky
Alex Savitsky

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

Ricardo Zanini
Ricardo Zanini

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

Related Questions