Jbang camel app not able to expose jetty component based route - apache-camel

When using the jbang cli jbang RestCamelJbang.java below code expose the REST endpoint successfully. Able to access the endpint at 8080
///usr/bin/env jbang "$0" "$0" : exit $?
// camel-k: language=java
//DEPS org.apache.camel:camel-bom:3.20.1#pom
//DEPS org.apache.camel:camel-core
//DEPS org.apache.camel:camel-main
//DEPS org.apache.camel:camel-jetty
//DEPS org.slf4j:slf4j-nop:2.0.6
//DEPS org.slf4j:slf4j-api:2.0.6
import org.apache.camel.*;
import org.apache.camel.builder.*;
import org.apache.camel.main.*;
import org.apache.camel.spi.*;
import static java.lang.System.*;
public class RestCamelJbang{
public static void main(String ... args) throws Exception{
out.println("Starting camel route...");
setProperty("org.slf4j.simpleLogger.logFile", "System.out");
Main main = new Main();
main.configure().addRoutesBuilder(new RouteBuilder(){
public void configure() throws Exception{
out.println("Camel configuration started...");
from("jetty:http://localhost:8080/hello")
.transform().simple("First Message of Camel");
}
});
main.run();
}
}
When using the Jbang Camel app camel run FirstCamel.java command with the jetty component, there are NO exception in the console but states 0 route started.
The endpoint http://localhost:8080/hello there is no response.
Am I missing something here, do we need some sort of server to run it?
///usr/bin/env jbang "$0" "$0" : exit $?
// camel-k: language=java
import org.apache.camel.*;
import org.apache.camel.builder.*;
import org.apache.camel.main.*;
import org.apache.camel.spi.*;
public class FirstCamel extends RouteBuilder{
#Override
public void configure() throws Exception{
from("jetty:http://localhost:8081/hello")
.transform().simple("First Message of Camel")
.log("${body}");
}
}
Console ouput
2023-02-13 21:10:22.056 INFO 6884 --- [ main] org.apache.camel.main.MainSupport : Apache Camel (JBang) 3.20.1 is starting
2023-02-13 21:10:22.511 INFO 6884 --- [ main] org.apache.camel.main.MainSupport : Using Java 17.0.1 with PID 6884. Started by thirumurthi in C:\thiru\learn\camel\camel_lessons\lesson
2023-02-13 21:10:22.543 INFO 6884 --- [ main] he.camel.cli.connector.LocalCliConnector : Camel CLI enabled (local)
2023-02-13 21:10:24.180 INFO 6884 --- [ main] .main.download.MavenDependencyDownloader : Downloaded: org.apache.camel:camel-rest:3.20.1 (took: 1s55ms)
2023-02-13 21:10:24.471 INFO 6884 --- [ main] e.camel.impl.engine.AbstractCamelContext : Apache Camel 3.20.1 (CamelJBang) is starting
2023-02-13 21:10:24.893 INFO 6884 --- [ main] e.camel.impl.engine.AbstractCamelContext : Routes startup (started:0)
2023-02-13 21:10:24.893 INFO 6884 --- [ main] e.camel.impl.engine.AbstractCamelContext : Apache Camel 3.20.1 (CamelJBang) started in 950ms (build:289ms init:241ms start:420ms JVM-uptime:5s)
Below code works when I use the rest DSL with camel run WelcomeRoute.java.
import org.apache.camel.*;
import org.apache.camel.builder.RouteBuilder;
public class WelcomeRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
restConfiguration().bindingMode("auto");
rest("/api")
.get("/demo/{info}")
.to("log:info")
.to("direct:msg");
from("direct:msg")
.transform().simple("msg received - ${header.info}");
}
}

When using Camel JBang run then its for running Camel routes (not Java Main classes). So the first code is not valid.
Camel JBang detects Java source that are RouteBuilder so your class should extend this class, like the 2nd and 3rd code examples.
There has been some troubles with Java 11 and older Camel releases to use .java source with java imports. That works with Java 17, so upgrade if you can. Otherwise you may need to use FQN classnames instead of imports.

Related

Apache camel pollEnrich strangeness

I am having a number of type conversion issues using the Java DSL with Camel 3.14.3. For a simple example I have a route that uses a direct endpoint to trigger a pollEnrich for a file endpoint.
public class BasicRoute extends RouteBuilder {
#Override
public void configure() {
from("direct:test")
.pollEnrich("file://watchDirectory", 10000)
.to("mock:result");
}
}
When the route starts I get the following exception...
Exception in thread "main" org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> PollEnrich[constant{file://watchDirectory}] <<< in route: Route(route1)[From[direct:test] -> [PollEnrich[constant{file... because of Error parsing [10000] as a java.time.Duration.
...
Caused by: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: java.lang.String to the required type: java.time.Duration with value 10000
I am running this within a simple OG java app, so I am sure I am missing something in the context initialization, but I cannot find it.

Why is CamelExchangesFailed_total metrics not increased?

I have a Apache Camel application which is monitored by Prometheus. Therefore, I added Micrometer to my POM (see Spring Boot Auto-Configuration) and MicrometerRoutePolicyFactory to my application (see Using Micrometer Route Policy Factory). But the metric CamelExchangesFailed_total doesn't change, althought a route failed.
Source
#SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
#Bean
public MicrometerRoutePolicyFactory micrometerRoutePolicyFactory() {
return new MicrometerRoutePolicyFactory();
}
#Bean
public EndpointRouteBuilder route() {
return new EndpointRouteBuilder() {
#Override
public void configure() throws Exception {
errorHandler(deadLetterChannel("log:dead"));
from(timer("testTimer").repeatCount(1)).throwException(new RuntimeException());
}
};
}
}
Logs
INFO 5060 --- [ restartedMain] o.a.c.i.e.InternalRouteStartupManager : Route: route1 started and consuming from: timer://testTimer
INFO 5060 --- [ restartedMain] o.a.c.impl.engine.AbstractCamelContext : Total 1 routes, of which 1 are started
INFO 5060 --- [ restartedMain] o.a.c.impl.engine.AbstractCamelContext : Apache Camel 3.5.0 (camel-1) started in 0.007 seconds
INFO 5060 --- [ restartedMain] test.TestApplication : Started TestApplication in 6.626 seconds (JVM running for 7.503)
INFO 5060 --- [on(3)-127.0.0.1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
INFO 5060 --- [on(3)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
INFO 5060 --- [on(3)-127.0.0.1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
INFO 5060 --- [mer://testTimer] dead : Exchange[ExchangePattern: InOnly, BodyType: null, Body: [Body is null]]
Metrics
# HELP CamelExchangesFailed_total
# TYPE CamelExchangesFailed_total counter
CamelExchangesFailed_total{application="test",camelContext="camel-1",routeId="route1",serviceName="MicrometerRoutePolicyService",} 0.0
# HELP CamelExchangesSucceeded_total
# TYPE CamelExchangesSucceeded_total counter
CamelExchangesSucceeded_total{application="test",camelContext="camel-1",routeId="route1",serviceName="MicrometerRoutePolicyService",} 1.0
Resaerch
If I remove the custom error handler, the metric CamelExchangesFailed_total is increased, but then the default error handler is used, which is not desired for some reasons.
Question
Why is CamelExchangesFailed_total metrics not increased? Is there any way to count all failed routes with a custom error handler?
Apache Camel LTS version 3.7.0 added a new metric CamelExchangesFailuresHandled_total, which is a counter of handled errors, see CAMEL-15908:
Similar to CAMEL-15255, there are some additional counter metrics we could add to the MicrometerRoutePolicy for:
Total exchanges processed
Number of failures handled
Number of external redeliveries
Metrics
# HELP CamelExchangesFailed_total
# TYPE CamelExchangesFailed_total counter
CamelExchangesFailed_total{application="test",camelContext="camel-1",routeId="route1",serviceName="MicrometerRoutePolicyService",} 0.0
# HELP CamelExchangesSucceeded_total
# TYPE CamelExchangesSucceeded_total counter
CamelExchangesSucceeded_total{application="test",camelContext="camel-1",routeId="route1",serviceName="MicrometerRoutePolicyService",} 1.0
# HELP CamelExchangesFailuresHandled_total
# TYPE CamelExchangesFailuresHandled_total counter
CamelExchangesFailuresHandled_total{application="test",camelContext="camel-1",routeId="route1",serviceName="MicrometerRoutePolicyService",} 1.0

Camel route with Spring Batch: No JobLauncher

I'm deploying a Spring Batch job triggered by a Camel route. Here is the Spring Batch config:
#Configuration
#EnableBatchProcessing
public class JobConfig
{
...
#Bean(name = "personJob")
public Job personJob(JobCompletionNotificationListener personListener, Step personStep)
{
return jobBuilderFactory
.get(...)
.incrementer(new RunIdIncrementer())
.listener(...)
.flow(...)
.end()
.build();
}
...
The Camel route looks like this:
#ApplicationScoped
public class MyRouteBuilder extends RouteBuilder
{
#Override
public void configure() throws Exception
{
from("file://...")
...
.to("spring-batch:personJob?jobLauncherRef=jobLauncher");
}
Running the route above raises the following exception:
[ERROR] Caused by: org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: spring-batch://personJob?jobLauncherRef=jobLauncher due to: No JobLauncher named jobLauncher found in the registry.
[ERROR] Caused by: java.lang.IllegalStateException: No JobLauncher named jobLauncher found in the registry."}}}}
However, the documentation clearly states:
The #EnableBatchProcessing works similarly to the other #Enable*
annotations in the Spring family. In this case, #EnableBatchProcessing
provides a base configuration for building batch jobs. Within this
base configuration, an instance of StepScope is created in addition to
a number of beans made available to be autowired:
JobRepository: bean name "jobRepository"
JobLauncher: bean name "jobLauncher"
...
So, there should be a bean named "jobLauncher" of the type JobLauncher. Why isn't it found in the registry ?
Many thanks in advance,
Seymour

FailedToStartRouteException exception while using camel-spring-boot, amqp and kafka starters with SpringBoot, unable to find connectionFactory bean

I am creating an application using Apache Camel to transfer messages from AMQP to Kafka. Code can also be seen here - https://github.com/prashantbhardwaj/qpid-to-kafka-using-camel
I thought of creating it as standalone SpringBoot app using spring, amqp and kafka starters. Created a route like
#Component
public class QpidToKafkaRoute extends RouteBuilder {
public void configure() throws Exception {
from("amqp:queue:destinationName")
.to("kafka:topic");
}
}
And SpringBoot application configuration is
#SpringBootApplication
public class CamelSpringJmsKafkaApplication {
public static void main(String[] args) {
SpringApplication.run(CamelSpringJmsKafkaApplication.class, args);
}
#Bean
public JmsConnectionFactory jmsConnectionFactory(#Value("${qpidUser}") String qpidUser, #Value("${qpidPassword}") String qpidPassword, #Value("${qpidBrokerUrl}") String qpidBrokerUrl) {
JmsConnectionFactory jmsConnectionFactory = new JmsConnectionFactory(qpidPassword, qpidPassword, qpidBrokerUrl);
return jmsConnectionFactory;
}
#Bean
#Primary
public CachingConnectionFactory jmsCachingConnectionFactory(JmsConnectionFactory jmsConnectionFactory) {
CachingConnectionFactory cachingConnectionFactory = new CachingConnectionFactory(jmsConnectionFactory);
return cachingConnectionFactory;
}
jmsConnectionFactory bean which is created using Spring Bean annotation should be picked by amqp starter and should be injected into the route. But it is not happening. When I started this application, I got following exception -
org.apache.camel.FailedToStartRouteException: Failed to start route route1 because of Route(route1)[From[amqp:queue:destinationName] -> [To[kafka:.
Caused by: java.lang.IllegalArgumentException: connectionFactory must be specified
If I am not wrong connectionFactory should be created automatically if I pass right properties in application.properties file.
My application.properties file looks like :
camel.springboot.main-run-controller = true
camel.component.amqp.enabled = true
camel.component.amqp.connection-factory = jmsCachingConnectionFactory
camel.component.amqp.async-consumer = true
camel.component.amqp.concurrent-consumers = 1
camel.component.amqp.map-jms-message = true
camel.component.amqp.test-connection-on-startup = true
camel.component.kafka.brokers = localhost:9092
qpidBrokerUrl = amqp://localhost:5672?jms.username=guest&jms.password=guest&jms.clientID=clientid2&amqp.vhost=default
qpidUser = guest
qpidPassword = guest
Could you please help suggest why during autoconfiguring connectionFactory object is not being used? When I debug this code, I can clearly see that connectionFactory bean is getting created.
I can even see one more log line -
CamelContext has only been running for less than a second. If you intend to run Camel for a longer time then you can set the property camel.springboot.main-run-controller=true in application.properties or add spring-boot-starter-web JAR to the classpath.
however if you see my application.properties file, required property is present at the very first line.
One more log line, I can see at the beginning of application startup -
[main] trationDelegate$BeanPostProcessorChecker : Bean 'org.apache.camel.spring.boot.CamelAutoConfiguration' of type [org.apache.camel.spring.boot.CamelAutoConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
Is this log line suggesting anything?
Note - One interesting fact that exactly same code was running fine last night, just restarted my desktop and there is not even a single word changed and now it is throwing exception.
This just refers to an interface
camel.component.amqp.connection-factory = javax.jms.ConnectionFactory
Instead it should refer to an existing factory instance, such as
camel.component.amqp.connection-factory = #myFactory
Which you can setup via spring boot #Bean annotation style.

filter jms message with xquery, using apache camel wildfly

I have problem to use xquery on a JMS message using apache camel and
wildfly.
My code reads from an jms queue and try to filter the message
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.cdi.ContextName;
import org.apache.camel.component.jms.JmsComponent;
import org.wildfly.extension.camel.CamelAware;
import javax.annotation.Resource;
import javax.ejb.Startup;
import javax.enterprise.context.ApplicationScoped;
import javax.jms.ConnectionFactory;
#Startup
#CamelAware
#ApplicationScoped
#ContextName("test")
class MyRouteBuilder extends RouteBuilder {
#Resource(mappedName = "java:jboss/DefaultJMSConnectionFactory")
private ConnectionFactory connectionFactory;
#Override
public void configure() throws Exception {
getContext().addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
from("jms:queue:test1").
routeId("test").
to("log:jms?showAll=true").
filter().xquery("fn:contains(//person/name/text(),'james')").
to("file://Users/asse/Outbound");
When I run the code with the message
<person><name>james</name><person> I get the error:
Message History
--------------------------------------------------------------------------------------------------------------------------------------- RouteId ProcessorId Processor
Elapsed (ms) [test ] [test ]
[jms://queue:test1
] [ 5] [test ] [to7 ]
[log:jms?showAll=true
] [ 1] [test ] [filter7 ]
[filter[xquery{XQuery[net.sf.saxon.query.XQueryExpression#3af367ad]}]
] [ 2]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------: org.apache.camel.RuntimeExpressionException:
java.lang.NullPointerException: External object cannot wrap a Java
null at
org.apache.camel.component.xquery.XQueryBuilder.matches(XQueryBuilder.java:220)
at
org.apache.camel.processor.FilterProcessor.matches(FilterProcessor.java:65)
at
org.apache.camel.processor.FilterProcessor.process(FilterProcessor.java:51)
at
org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
at
org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:542)
at
org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:197)
I don't understand why! Can anyone help me with this problem??
Encountered the same issue with standalone camel 2.18.1.
I believe this is a bug in camel caused by upgrading to Saxon version 9.7.0, which no longer allows null values to be put into query context
The bug is in class org.apache.camel.component.xquery.XQueryBuilder. It attempt to add all Exchange headers and properties to query execution context in method org.apache.camel.component.xquery.XQueryBuilder#configureQuery. If any of the headers or properties have null values (and in case of JMS message there will be lots of headers), an exception is thrown.
I was able to reproduce the issue and it seems it is not the only problem with xquery in camel 2.18
I've logged a jira issue https://issues.apache.org/jira/browse/CAMEL-10653

Resources